19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
49ec7b004SRick Macklem * Copyright (c) 1989, 1993
59ec7b004SRick Macklem * The Regents of the University of California. All rights reserved.
69ec7b004SRick Macklem *
79ec7b004SRick Macklem * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem *
109ec7b004SRick Macklem * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem * are met:
139ec7b004SRick Macklem * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem * documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem * may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem * without specific prior written permission.
219ec7b004SRick Macklem *
229ec7b004SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem * SUCH DAMAGE.
339ec7b004SRick Macklem *
349ec7b004SRick Macklem */
359ec7b004SRick Macklem
369ec7b004SRick Macklem #include <sys/cdefs.h>
379ec7b004SRick Macklem /*
389ec7b004SRick Macklem * These functions support the macros and help fiddle mbuf chains for
399ec7b004SRick Macklem * the nfs op functions. They do things like create the rpc header and
409ec7b004SRick Macklem * copy data between mbuf chains and uio lists.
419ec7b004SRick Macklem */
4280405bcfSRick Macklem #include "opt_inet.h"
43f7258644SRick Macklem #include "opt_inet6.h"
44f7258644SRick Macklem
459ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
46896516e5SRick Macklem #include <fs/nfsclient/nfsmount.h>
479ec7b004SRick Macklem
48c057a378SRick Macklem #include <sys/extattr.h>
49c057a378SRick Macklem
5084be7e09SRick Macklem #include <security/mac/mac_framework.h>
5184be7e09SRick Macklem
524476c1deSRick Macklem #include <vm/vm_param.h>
534476c1deSRick Macklem
549ec7b004SRick Macklem /*
559ec7b004SRick Macklem * Data items converted to xdr at startup, since they are constant
569ec7b004SRick Macklem * This is kinda hokey, but may save a little time doing byte swaps
579ec7b004SRick Macklem */
589ec7b004SRick Macklem u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
599ec7b004SRick Macklem
609ec7b004SRick Macklem /* And other global data */
619ec7b004SRick Macklem nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
629ec7b004SRick Macklem NFFIFO, NFNON };
63ba8cc6d7SMateusz Guzik __enum_uint8(vtype) newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
64ba8cc6d7SMateusz Guzik __enum_uint8(vtype) nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
659ec7b004SRick Macklem struct timeval nfsboottime; /* Copy boottime once, so it never changes */
669ec7b004SRick Macklem int nfscl_ticks;
679ec7b004SRick Macklem int nfsrv_useacl = 1;
689ec7b004SRick Macklem struct nfsreqhead nfsd_reqq;
699ec7b004SRick Macklem int nfsrv_lease = NFSRV_LEASE;
709ec7b004SRick Macklem int ncl_mbuf_mlen = MLEN;
7190d2dfabSRick Macklem int nfsrv_doflexfile = 0;
729ec7b004SRick Macklem NFSNAMEIDMUTEX;
739ec7b004SRick Macklem NFSSOCKMUTEX;
7484be7e09SRick Macklem extern int nfsrv_lughashsize;
7590d2dfabSRick Macklem extern struct mtx nfsrv_dslock_mtx;
7690d2dfabSRick Macklem extern volatile int nfsrv_devidcnt;
7790d2dfabSRick Macklem extern int nfscl_debuglevel;
7890d2dfabSRick Macklem extern struct nfsdevicehead nfsrv_devidhead;
79c338c94dSRick Macklem extern struct nfsstatsv1 nfsstatsv1;
80ee29e6f3SRick Macklem extern uint32_t nfs_srvmaxio;
819ec7b004SRick Macklem
82f0db2b60SRick Macklem NFSD_VNET_DEFINE(int, nfsd_enable_stringtouid) = 0;
83f0db2b60SRick Macklem NFSD_VNET_DEFINE(struct nfssockreq, nfsrv_nfsuserdsock);
84f0db2b60SRick Macklem NFSD_VNET_DEFINE(nfsuserd_state, nfsrv_nfsuserd) = NOTRUNNING;
85f0db2b60SRick Macklem NFSD_VNET_DEFINE(uid_t, nfsrv_defaultuid) = UID_NOBODY;
86f0db2b60SRick Macklem NFSD_VNET_DEFINE(gid_t, nfsrv_defaultgid) = GID_NOGROUP;
87f0db2b60SRick Macklem
88f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(int, nfsrv_userdupcalls) = 0;
89f0db2b60SRick Macklem
901d2fef9bSEdward Tomasz Napierala SYSCTL_DECL(_vfs_nfs);
91f0db2b60SRick Macklem
92f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(int, nfs_enable_uidtostring) = 0;
93f0db2b60SRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring,
94f0db2b60SRick Macklem CTLFLAG_NFSD_VNET | CTLFLAG_RW, &NFSD_VNET_NAME(nfs_enable_uidtostring), 0,
95f0db2b60SRick Macklem "Make nfs always send numeric owner_names");
961d2fef9bSEdward Tomasz Napierala
9790d2dfabSRick Macklem int nfsrv_maxpnfsmirror = 1;
9890d2dfabSRick Macklem SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
9990d2dfabSRick Macklem &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
10090d2dfabSRick Macklem
1019ec7b004SRick Macklem /*
1029ec7b004SRick Macklem * This array of structures indicates, for V4:
1039ec7b004SRick Macklem * retfh - which of 3 types of calling args are used
1049ec7b004SRick Macklem * 0 - doesn't change cfh or use a sfh
1059ec7b004SRick Macklem * 1 - replaces cfh with a new one (unless it returns an error status)
1069ec7b004SRick Macklem * 2 - uses cfh and sfh
1079ec7b004SRick Macklem * needscfh - if the op wants a cfh and premtime
1089ec7b004SRick Macklem * 0 - doesn't use a cfh
1099ec7b004SRick Macklem * 1 - uses a cfh, but doesn't want pre-op attributes
1109ec7b004SRick Macklem * 2 - uses a cfh and wants pre-op attributes
1119ec7b004SRick Macklem * savereply - indicates a non-idempotent Op
1129ec7b004SRick Macklem * 0 - not non-idempotent
1139ec7b004SRick Macklem * 1 - non-idempotent
1149ec7b004SRick Macklem * Ops that are ordered via seqid# are handled separately from these
1159ec7b004SRick Macklem * non-idempotent Ops.
1169ec7b004SRick Macklem * Define it here, since it is used by both the client and server.
1179ec7b004SRick Macklem */
118c057a378SRick Macklem struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
119b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
120b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
121b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */
122b2fc0141SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */
123b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */
124b2fc0141SRick Macklem { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */
125b2fc0141SRick Macklem { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */
126b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */
127b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */
128b2fc0141SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */
129b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */
130b2fc0141SRick Macklem { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */
131b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */
132b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */
133b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */
134b2fc0141SRick Macklem { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */
135b2fc0141SRick Macklem { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */
136b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */
137b2fc0141SRick Macklem { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */
138b2fc0141SRick Macklem { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */
139b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */
140b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */
141b2fc0141SRick Macklem { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */
142b2fc0141SRick Macklem { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */
143b2fc0141SRick Macklem { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */
144b2fc0141SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */
145b2fc0141SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */
146b2fc0141SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */
147b2fc0141SRick Macklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */
148b2fc0141SRick Macklem { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */
149b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */
150b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */
151b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */
152b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */
153b2fc0141SRick Macklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */
154b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */
155b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */
156330aa8acSRick Macklem { 0, 2, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Verify (AppWrite) */
157b2fc0141SRick Macklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */
158b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */
159b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */
1609442a64eSRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */
161b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */
162b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */
163b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */
164b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */
165b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */
166b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */
167b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */
1683e5ba2e1SRick Macklem { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */
169b2fc0141SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */
1703e5ba2e1SRick Macklem { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */
171947bd247SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */
172b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */
173b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */
174b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */
175b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */
176b2fc0141SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
1772242bc81SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
178c057a378SRick Macklem { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
179c057a378SRick Macklem { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
180c057a378SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
1813ad1e1c1SRick Macklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Deallocate */
182c057a378SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* IO Advise */
183c057a378SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Error */
184c057a378SRick Macklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Stats */
185c057a378SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */
186c057a378SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */
187c057a378SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */
188c057a378SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */
189c057a378SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */
190c057a378SRick Macklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */
191c057a378SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getxattr */
192c057a378SRick Macklem { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Setxattr */
193c057a378SRick Macklem { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Listxattrs */
194c057a378SRick Macklem { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
1959ec7b004SRick Macklem };
1969ec7b004SRick Macklem
1979ec7b004SRick Macklem static int ncl_mbuf_mhlen = MHLEN;
19884be7e09SRick Macklem struct nfsrv_lughash {
19984be7e09SRick Macklem struct mtx mtx;
20084be7e09SRick Macklem struct nfsuserhashhead lughead;
20184be7e09SRick Macklem };
202f0db2b60SRick Macklem
203f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(int, nfsrv_usercnt) = 0;
204f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(int, nfsrv_dnsnamelen) = 0;
205f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(int, nfsrv_usermax) = 999999999;
206f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsuserhash) = NULL;
207f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsusernamehash) = NULL;
208f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgrouphash) = NULL;
209f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgroupnamehash) = NULL;
210f0db2b60SRick Macklem NFSD_VNET_DEFINE_STATIC(u_char *, nfsrv_dnsname) = NULL;
2119ec7b004SRick Macklem
2129ec7b004SRick Macklem /*
2139ec7b004SRick Macklem * This static array indicates whether or not the RPC generates a large
2149ec7b004SRick Macklem * reply. This is used by nfs_reply() to decide whether or not an mbuf
2159ec7b004SRick Macklem * cluster should be allocated. (If a cluster is required by an RPC
2169ec7b004SRick Macklem * marked 0 in this array, the code will still work, just not quite as
2179ec7b004SRick Macklem * efficiently.)
2189ec7b004SRick Macklem */
219c057a378SRick Macklem static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
2209ec7b004SRick Macklem 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,
221c057a378SRick Macklem 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
222330aa8acSRick Macklem 1, 0, 0, 1, 0, 0, 0, 0, 0 };
2239ec7b004SRick Macklem
2249ec7b004SRick Macklem /* local functions */
2259ec7b004SRick Macklem static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
2269ec7b004SRick Macklem static void nfsv4_wanted(struct nfsv4lock *lp);
2272d90ef47SRick Macklem static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
228f32bf292SEdward Tomasz Napierala static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
22984be7e09SRick Macklem static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
2309ec7b004SRick Macklem static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
2319ec7b004SRick Macklem int *, int *);
2329ec7b004SRick Macklem static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
2339ec7b004SRick Macklem
234c338c94dSRick Macklem static struct {
235c338c94dSRick Macklem int op;
236c338c94dSRick Macklem int opcnt;
237c338c94dSRick Macklem const u_char *tag;
238c338c94dSRick Macklem int taglen;
239c057a378SRick Macklem } nfsv4_opmap[NFSV42_NPROCS] = {
240c338c94dSRick Macklem { 0, 1, "Null", 4 },
241c338c94dSRick Macklem { NFSV4OP_GETATTR, 1, "Getattr", 7, },
242c338c94dSRick Macklem { NFSV4OP_SETATTR, 2, "Setattr", 7, },
243c338c94dSRick Macklem { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
244c338c94dSRick Macklem { NFSV4OP_ACCESS, 2, "Access", 6, },
245c338c94dSRick Macklem { NFSV4OP_READLINK, 2, "Readlink", 8, },
246c338c94dSRick Macklem { NFSV4OP_READ, 1, "Read", 4, },
247c338c94dSRick Macklem { NFSV4OP_WRITE, 2, "Write", 5, },
248c338c94dSRick Macklem { NFSV4OP_OPEN, 5, "Open", 4, },
249c338c94dSRick Macklem { NFSV4OP_CREATE, 5, "Create", 6, },
250c338c94dSRick Macklem { NFSV4OP_CREATE, 1, "Create", 6, },
251c338c94dSRick Macklem { NFSV4OP_CREATE, 3, "Create", 6, },
252c338c94dSRick Macklem { NFSV4OP_REMOVE, 1, "Remove", 6, },
253c338c94dSRick Macklem { NFSV4OP_REMOVE, 1, "Remove", 6, },
254c338c94dSRick Macklem { NFSV4OP_SAVEFH, 5, "Rename", 6, },
255c338c94dSRick Macklem { NFSV4OP_SAVEFH, 4, "Link", 4, },
256c338c94dSRick Macklem { NFSV4OP_READDIR, 2, "Readdir", 7, },
257c338c94dSRick Macklem { NFSV4OP_READDIR, 2, "Readdir", 7, },
258c338c94dSRick Macklem { NFSV4OP_GETATTR, 1, "Getattr", 7, },
259c338c94dSRick Macklem { NFSV4OP_GETATTR, 1, "Getattr", 7, },
260c338c94dSRick Macklem { NFSV4OP_GETATTR, 1, "Getattr", 7, },
261c338c94dSRick Macklem { NFSV4OP_COMMIT, 2, "Commit", 6, },
262c338c94dSRick Macklem { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
263c338c94dSRick Macklem { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
264c338c94dSRick Macklem { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
265c338c94dSRick Macklem { NFSV4OP_LOCK, 1, "Lock", 4, },
266c338c94dSRick Macklem { NFSV4OP_LOCKU, 1, "LockU", 5, },
267c338c94dSRick Macklem { NFSV4OP_OPEN, 2, "Open", 4, },
268c338c94dSRick Macklem { NFSV4OP_CLOSE, 1, "Close", 5, },
269c338c94dSRick Macklem { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
270c338c94dSRick Macklem { NFSV4OP_LOCKT, 1, "LockT", 5, },
271c338c94dSRick Macklem { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
272c338c94dSRick Macklem { NFSV4OP_RENEW, 1, "Renew", 5, },
273c338c94dSRick Macklem { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
274c338c94dSRick Macklem { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
275c338c94dSRick Macklem { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
276c338c94dSRick Macklem { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
277c338c94dSRick Macklem { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
278c338c94dSRick Macklem { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
279c338c94dSRick Macklem { NFSV4OP_GETATTR, 1, "Getacl", 6, },
280c338c94dSRick Macklem { NFSV4OP_SETATTR, 1, "Setacl", 6, },
281c338c94dSRick Macklem { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
282c338c94dSRick Macklem { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
283c338c94dSRick Macklem { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
284c338c94dSRick Macklem { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
285c338c94dSRick Macklem { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
286c338c94dSRick Macklem { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
287c338c94dSRick Macklem { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
288c338c94dSRick Macklem { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
289c338c94dSRick Macklem { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
290c338c94dSRick Macklem { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
291c338c94dSRick Macklem { NFSV4OP_WRITE, 1, "WriteDS", 7, },
292c338c94dSRick Macklem { NFSV4OP_READ, 1, "ReadDS", 6, },
293c338c94dSRick Macklem { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
294c338c94dSRick Macklem { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
295c338c94dSRick Macklem { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
296c057a378SRick Macklem { NFSV4OP_IOADVISE, 1, "Advise", 6, },
297c057a378SRick Macklem { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
298cc760de2SRick Macklem { NFSV4OP_SAVEFH, 5, "Copy", 4, },
299c057a378SRick Macklem { NFSV4OP_SEEK, 2, "Seek", 4, },
300c057a378SRick Macklem { NFSV4OP_SEEK, 1, "SeekDS", 6, },
301c057a378SRick Macklem { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
302c057a378SRick Macklem { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
303c057a378SRick Macklem { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
304c057a378SRick Macklem { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
3057763814fSRick Macklem { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, },
3063ad1e1c1SRick Macklem { NFSV4OP_LOOKUP, 5, "LookupOpen", 10, },
3073ad1e1c1SRick Macklem { NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, },
30844744f75SRick Macklem { NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, },
309330aa8acSRick Macklem { NFSV4OP_VERIFY, 3, "AppendWrite", 11, },
310c338c94dSRick Macklem };
311c338c94dSRick Macklem
312c338c94dSRick Macklem /*
313c338c94dSRick Macklem * NFS RPCS that have large request message size.
314c338c94dSRick Macklem */
315c057a378SRick Macklem static int nfs_bigrequest[NFSV42_NPROCS] = {
316c338c94dSRick Macklem 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
317c338c94dSRick Macklem 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31844744f75SRick Macklem 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
319330aa8acSRick Macklem 0, 1
320c338c94dSRick Macklem };
321c338c94dSRick Macklem
322c338c94dSRick Macklem /*
323c338c94dSRick Macklem * Start building a request. Mostly just put the first file handle in
324c338c94dSRick Macklem * place.
325c338c94dSRick Macklem */
326b9cc3262SRyan Moeller void
nfscl_reqstart(struct nfsrv_descript * nd,int procnum,struct nfsmount * nmp,u_int8_t * nfhp,int fhlen,u_int32_t ** opcntpp,struct nfsclsession * sep,int vers,int minorvers,struct ucred * cred)327c338c94dSRick Macklem nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
328c338c94dSRick Macklem u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
32940ada74eSRick Macklem int vers, int minorvers, struct ucred *cred)
330c338c94dSRick Macklem {
331c338c94dSRick Macklem struct mbuf *mb;
332c338c94dSRick Macklem u_int32_t *tl;
333c338c94dSRick Macklem int opcnt;
334c338c94dSRick Macklem nfsattrbit_t attrbits;
335c338c94dSRick Macklem
336c338c94dSRick Macklem /*
337c338c94dSRick Macklem * First, fill in some of the fields of nd.
338c338c94dSRick Macklem */
339c338c94dSRick Macklem nd->nd_slotseq = NULL;
340c338c94dSRick Macklem if (vers == NFS_VER4) {
341c338c94dSRick Macklem nd->nd_flag = ND_NFSV4 | ND_NFSCL;
342c338c94dSRick Macklem if (minorvers == NFSV41_MINORVERSION)
343c338c94dSRick Macklem nd->nd_flag |= ND_NFSV41;
344c057a378SRick Macklem else if (minorvers == NFSV42_MINORVERSION)
345c057a378SRick Macklem nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
346c338c94dSRick Macklem } else if (vers == NFS_VER3)
347c338c94dSRick Macklem nd->nd_flag = ND_NFSV3 | ND_NFSCL;
348c338c94dSRick Macklem else {
349c338c94dSRick Macklem if (NFSHASNFSV4(nmp)) {
350c338c94dSRick Macklem nd->nd_flag = ND_NFSV4 | ND_NFSCL;
351c057a378SRick Macklem if (nmp->nm_minorvers == 1)
352c338c94dSRick Macklem nd->nd_flag |= ND_NFSV41;
353c057a378SRick Macklem else if (nmp->nm_minorvers == 2)
354c057a378SRick Macklem nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
355c338c94dSRick Macklem } else if (NFSHASNFSV3(nmp))
356c338c94dSRick Macklem nd->nd_flag = ND_NFSV3 | ND_NFSCL;
357c338c94dSRick Macklem else
358c338c94dSRick Macklem nd->nd_flag = ND_NFSV2 | ND_NFSCL;
359c338c94dSRick Macklem }
360c338c94dSRick Macklem nd->nd_procnum = procnum;
361c338c94dSRick Macklem nd->nd_repstat = 0;
362808306ddSRick Macklem nd->nd_maxextsiz = 0;
363c338c94dSRick Macklem
364c338c94dSRick Macklem /*
365c338c94dSRick Macklem * Get the first mbuf for the request.
366c338c94dSRick Macklem */
367c338c94dSRick Macklem if (nfs_bigrequest[procnum])
368c338c94dSRick Macklem NFSMCLGET(mb, M_WAITOK);
369c338c94dSRick Macklem else
370c338c94dSRick Macklem NFSMGET(mb);
371c948a17aSRick Macklem mb->m_len = 0;
372c338c94dSRick Macklem nd->nd_mreq = nd->nd_mb = mb;
3734476c1deSRick Macklem nd->nd_bpos = mtod(mb, char *);
374c338c94dSRick Macklem
3754adb28c0SRick Macklem /* For NFSPROC_NULL, there are no arguments. */
3764adb28c0SRick Macklem if (procnum == NFSPROC_NULL)
3774adb28c0SRick Macklem goto out;
3784adb28c0SRick Macklem
379c338c94dSRick Macklem /*
380c338c94dSRick Macklem * And fill the first file handle into the request.
381c338c94dSRick Macklem */
382c338c94dSRick Macklem if (nd->nd_flag & ND_NFSV4) {
383c338c94dSRick Macklem opcnt = nfsv4_opmap[procnum].opcnt +
384c338c94dSRick Macklem nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
385c338c94dSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) {
386c338c94dSRick Macklem opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
387c338c94dSRick Macklem if (procnum == NFSPROC_RENEW)
388c338c94dSRick Macklem /*
389c338c94dSRick Macklem * For the special case of Renew, just do a
390c338c94dSRick Macklem * Sequence Op.
391c338c94dSRick Macklem */
392c338c94dSRick Macklem opcnt = 1;
393c338c94dSRick Macklem else if (procnum == NFSPROC_WRITEDS ||
394c338c94dSRick Macklem procnum == NFSPROC_COMMITDS)
395c338c94dSRick Macklem /*
396c338c94dSRick Macklem * For the special case of a Writeor Commit to
397c338c94dSRick Macklem * a DS, the opcnt == 3, for Sequence, PutFH,
398c338c94dSRick Macklem * Write/Commit.
399c338c94dSRick Macklem */
400c338c94dSRick Macklem opcnt = 3;
401c338c94dSRick Macklem }
402c338c94dSRick Macklem /*
403c338c94dSRick Macklem * What should the tag really be?
404c338c94dSRick Macklem */
405c338c94dSRick Macklem (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
406c338c94dSRick Macklem nfsv4_opmap[procnum].taglen);
407c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
408c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV42) != 0)
409c057a378SRick Macklem *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
410c057a378SRick Macklem else if ((nd->nd_flag & ND_NFSV41) != 0)
411c338c94dSRick Macklem *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
412c338c94dSRick Macklem else
413c338c94dSRick Macklem *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
414c338c94dSRick Macklem if (opcntpp != NULL)
415c338c94dSRick Macklem *opcntpp = tl;
416c338c94dSRick Macklem *tl = txdr_unsigned(opcnt);
417c338c94dSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 &&
418c338c94dSRick Macklem nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
419c338c94dSRick Macklem if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
420c338c94dSRick Macklem 0)
421c338c94dSRick Macklem nd->nd_flag |= ND_LOOPBADSESS;
422c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
423c338c94dSRick Macklem *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
424c338c94dSRick Macklem if (sep == NULL) {
425c338c94dSRick Macklem sep = nfsmnt_mdssession(nmp);
42640ada74eSRick Macklem /*
42740ada74eSRick Macklem * For MDS mount sessions, check for bad
42840ada74eSRick Macklem * slots. If the caller does not want this
42940ada74eSRick Macklem * check to be done, the "cred" argument can
43040ada74eSRick Macklem * be passed in as NULL.
43140ada74eSRick Macklem */
432c338c94dSRick Macklem nfsv4_setsequence(nmp, nd, sep,
43340ada74eSRick Macklem nfs_bigreply[procnum], cred);
434c338c94dSRick Macklem } else
435c338c94dSRick Macklem nfsv4_setsequence(nmp, nd, sep,
43640ada74eSRick Macklem nfs_bigreply[procnum], NULL);
437c338c94dSRick Macklem }
438c338c94dSRick Macklem if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
439c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
440c338c94dSRick Macklem *tl = txdr_unsigned(NFSV4OP_PUTFH);
441695d87baSRick Macklem (void)nfsm_fhtom(nmp, nd, nfhp, fhlen, 0);
442c338c94dSRick Macklem if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
443c338c94dSRick Macklem == 2 && procnum != NFSPROC_WRITEDS &&
444c338c94dSRick Macklem procnum != NFSPROC_COMMITDS) {
445c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
446c338c94dSRick Macklem *tl = txdr_unsigned(NFSV4OP_GETATTR);
447c338c94dSRick Macklem /*
448c338c94dSRick Macklem * For Lookup Ops, we want all the directory
449c338c94dSRick Macklem * attributes, so we can load the name cache.
450c338c94dSRick Macklem */
451c338c94dSRick Macklem if (procnum == NFSPROC_LOOKUP ||
4523ad1e1c1SRick Macklem procnum == NFSPROC_LOOKUPP ||
4533ad1e1c1SRick Macklem procnum == NFSPROC_LOOKUPOPEN)
454c338c94dSRick Macklem NFSGETATTR_ATTRBIT(&attrbits);
455c338c94dSRick Macklem else {
456c338c94dSRick Macklem NFSWCCATTR_ATTRBIT(&attrbits);
45721de450aSRick Macklem /* For AppendWrite, get the size. */
45821de450aSRick Macklem if (procnum == NFSPROC_APPENDWRITE)
45921de450aSRick Macklem NFSSETBIT_ATTRBIT(&attrbits,
46021de450aSRick Macklem NFSATTRBIT_SIZE);
461c338c94dSRick Macklem nd->nd_flag |= ND_V4WCCATTR;
462c338c94dSRick Macklem }
463c338c94dSRick Macklem (void) nfsrv_putattrbit(nd, &attrbits);
464c338c94dSRick Macklem }
465c338c94dSRick Macklem }
466c338c94dSRick Macklem if (procnum != NFSPROC_RENEW ||
467c338c94dSRick Macklem (nd->nd_flag & ND_NFSV41) == 0) {
468c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
469c338c94dSRick Macklem *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
470c338c94dSRick Macklem }
471c338c94dSRick Macklem } else {
472695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, nfhp, fhlen, 0);
473c338c94dSRick Macklem }
4744adb28c0SRick Macklem out:
475c057a378SRick Macklem if (procnum < NFSV42_NPROCS)
476c338c94dSRick Macklem NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
477c338c94dSRick Macklem }
478c338c94dSRick Macklem
479c338c94dSRick Macklem /*
480c338c94dSRick Macklem * Put a state Id in the mbuf list.
481c338c94dSRick Macklem */
482b9cc3262SRyan Moeller void
nfsm_stateidtom(struct nfsrv_descript * nd,nfsv4stateid_t * stateidp,int flag)483c338c94dSRick Macklem nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
484c338c94dSRick Macklem {
485c338c94dSRick Macklem nfsv4stateid_t *st;
486c338c94dSRick Macklem
487c338c94dSRick Macklem NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
488c338c94dSRick Macklem if (flag == NFSSTATEID_PUTALLZERO) {
489c338c94dSRick Macklem st->seqid = 0;
490c338c94dSRick Macklem st->other[0] = 0;
491c338c94dSRick Macklem st->other[1] = 0;
492c338c94dSRick Macklem st->other[2] = 0;
493c338c94dSRick Macklem } else if (flag == NFSSTATEID_PUTALLONE) {
494c338c94dSRick Macklem st->seqid = 0xffffffff;
495c338c94dSRick Macklem st->other[0] = 0xffffffff;
496c338c94dSRick Macklem st->other[1] = 0xffffffff;
497c338c94dSRick Macklem st->other[2] = 0xffffffff;
498c338c94dSRick Macklem } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
499c338c94dSRick Macklem st->seqid = 0;
500c338c94dSRick Macklem st->other[0] = stateidp->other[0];
501c338c94dSRick Macklem st->other[1] = stateidp->other[1];
502c338c94dSRick Macklem st->other[2] = stateidp->other[2];
503c338c94dSRick Macklem } else {
504c338c94dSRick Macklem st->seqid = stateidp->seqid;
505c338c94dSRick Macklem st->other[0] = stateidp->other[0];
506c338c94dSRick Macklem st->other[1] = stateidp->other[1];
507c338c94dSRick Macklem st->other[2] = stateidp->other[2];
508c338c94dSRick Macklem }
509c338c94dSRick Macklem }
510c338c94dSRick Macklem
511c338c94dSRick Macklem /*
512c338c94dSRick Macklem * Fill in the setable attributes. The full argument indicates whether
513c338c94dSRick Macklem * to fill in them all or just mode and time.
514c338c94dSRick Macklem */
515c338c94dSRick Macklem void
nfscl_fillsattr(struct nfsrv_descript * nd,struct vattr * vap,struct vnode * vp,int flags,u_int32_t rdev)516c338c94dSRick Macklem nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
517c338c94dSRick Macklem struct vnode *vp, int flags, u_int32_t rdev)
518c338c94dSRick Macklem {
519c338c94dSRick Macklem u_int32_t *tl;
520c338c94dSRick Macklem struct nfsv2_sattr *sp;
521c338c94dSRick Macklem nfsattrbit_t attrbits;
522194d8704SRick Macklem struct nfsnode *np;
523c338c94dSRick Macklem
524c338c94dSRick Macklem switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
525c338c94dSRick Macklem case ND_NFSV2:
526c338c94dSRick Macklem NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
527c338c94dSRick Macklem if (vap->va_mode == (mode_t)VNOVAL)
528c338c94dSRick Macklem sp->sa_mode = newnfs_xdrneg1;
529c338c94dSRick Macklem else
530c338c94dSRick Macklem sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
531c338c94dSRick Macklem if (vap->va_uid == (uid_t)VNOVAL)
532c338c94dSRick Macklem sp->sa_uid = newnfs_xdrneg1;
533c338c94dSRick Macklem else
534c338c94dSRick Macklem sp->sa_uid = txdr_unsigned(vap->va_uid);
535c338c94dSRick Macklem if (vap->va_gid == (gid_t)VNOVAL)
536c338c94dSRick Macklem sp->sa_gid = newnfs_xdrneg1;
537c338c94dSRick Macklem else
538c338c94dSRick Macklem sp->sa_gid = txdr_unsigned(vap->va_gid);
539c338c94dSRick Macklem if (flags & NFSSATTR_SIZE0)
540c338c94dSRick Macklem sp->sa_size = 0;
541c338c94dSRick Macklem else if (flags & NFSSATTR_SIZENEG1)
542c338c94dSRick Macklem sp->sa_size = newnfs_xdrneg1;
543c338c94dSRick Macklem else if (flags & NFSSATTR_SIZERDEV)
544c338c94dSRick Macklem sp->sa_size = txdr_unsigned(rdev);
545c338c94dSRick Macklem else
546c338c94dSRick Macklem sp->sa_size = txdr_unsigned(vap->va_size);
547c338c94dSRick Macklem txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
548c338c94dSRick Macklem txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
549c338c94dSRick Macklem break;
550c338c94dSRick Macklem case ND_NFSV3:
551c338c94dSRick Macklem if (vap->va_mode != (mode_t)VNOVAL) {
552c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
553c338c94dSRick Macklem *tl++ = newnfs_true;
554c338c94dSRick Macklem *tl = txdr_unsigned(vap->va_mode);
555c338c94dSRick Macklem } else {
556c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
557c338c94dSRick Macklem *tl = newnfs_false;
558c338c94dSRick Macklem }
559c338c94dSRick Macklem if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
560c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
561c338c94dSRick Macklem *tl++ = newnfs_true;
562c338c94dSRick Macklem *tl = txdr_unsigned(vap->va_uid);
563c338c94dSRick Macklem } else {
564c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
565c338c94dSRick Macklem *tl = newnfs_false;
566c338c94dSRick Macklem }
567c338c94dSRick Macklem if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
568c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
569c338c94dSRick Macklem *tl++ = newnfs_true;
570c338c94dSRick Macklem *tl = txdr_unsigned(vap->va_gid);
571c338c94dSRick Macklem } else {
572c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
573c338c94dSRick Macklem *tl = newnfs_false;
574c338c94dSRick Macklem }
575c338c94dSRick Macklem if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
576c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
577c338c94dSRick Macklem *tl++ = newnfs_true;
578c338c94dSRick Macklem txdr_hyper(vap->va_size, tl);
579c338c94dSRick Macklem } else {
580c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
581c338c94dSRick Macklem *tl = newnfs_false;
582c338c94dSRick Macklem }
583c338c94dSRick Macklem if (vap->va_atime.tv_sec != VNOVAL) {
584c338c94dSRick Macklem if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
585c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
586c338c94dSRick Macklem *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
587c338c94dSRick Macklem txdr_nfsv3time(&vap->va_atime, tl);
588c338c94dSRick Macklem } else {
589c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
590c338c94dSRick Macklem *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
591c338c94dSRick Macklem }
592c338c94dSRick Macklem } else {
593c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
594c338c94dSRick Macklem *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
595c338c94dSRick Macklem }
596c338c94dSRick Macklem if (vap->va_mtime.tv_sec != VNOVAL) {
597c338c94dSRick Macklem if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
598c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
599c338c94dSRick Macklem *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
600c338c94dSRick Macklem txdr_nfsv3time(&vap->va_mtime, tl);
601c338c94dSRick Macklem } else {
602c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
603c338c94dSRick Macklem *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
604c338c94dSRick Macklem }
605c338c94dSRick Macklem } else {
606c338c94dSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
607c338c94dSRick Macklem *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
608c338c94dSRick Macklem }
609c338c94dSRick Macklem break;
610c338c94dSRick Macklem case ND_NFSV4:
611c338c94dSRick Macklem NFSZERO_ATTRBIT(&attrbits);
6122477e88bSRick Macklem np = NULL;
6132477e88bSRick Macklem if (strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0)
6142477e88bSRick Macklem np = VTONFS(vp);
6152477e88bSRick Macklem if (vap->va_mode != (mode_t)VNOVAL) {
6162477e88bSRick Macklem if ((flags & NFSSATTR_NEWFILE) != 0 && np != NULL &&
6172477e88bSRick Macklem NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
6182477e88bSRick Macklem NFSATTRBIT_MODEUMASK))
6192477e88bSRick Macklem NFSSETBIT_ATTRBIT(&attrbits,
6202477e88bSRick Macklem NFSATTRBIT_MODEUMASK);
6212477e88bSRick Macklem else
622c338c94dSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
6232477e88bSRick Macklem }
624c338c94dSRick Macklem if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
625c338c94dSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
626c338c94dSRick Macklem if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
627c338c94dSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
628c338c94dSRick Macklem if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
629c338c94dSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
630c338c94dSRick Macklem if (vap->va_atime.tv_sec != VNOVAL)
631c338c94dSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
632c338c94dSRick Macklem if (vap->va_mtime.tv_sec != VNOVAL)
633c338c94dSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
634194d8704SRick Macklem /*
635194d8704SRick Macklem * We can only test for support of TimeCreate if
636194d8704SRick Macklem * the "vp" argument is for an NFS vnode.
637194d8704SRick Macklem */
6382477e88bSRick Macklem if (vap->va_birthtime.tv_sec != VNOVAL && np != NULL &&
6392477e88bSRick Macklem NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
640194d8704SRick Macklem NFSATTRBIT_TIMECREATE))
6412477e88bSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
642c338c94dSRick Macklem (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
643c338c94dSRick Macklem &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
644c338c94dSRick Macklem break;
645c338c94dSRick Macklem }
646c338c94dSRick Macklem }
6479ec7b004SRick Macklem
6489ec7b004SRick Macklem /*
6499ec7b004SRick Macklem * copies mbuf chain to the uio scatter/gather list
6509ec7b004SRick Macklem */
6519ec7b004SRick Macklem int
nfsm_mbufuio(struct nfsrv_descript * nd,struct uio * uiop,int siz)6529ec7b004SRick Macklem nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
6539ec7b004SRick Macklem {
6549ec7b004SRick Macklem char *mbufcp, *uiocp;
6559ec7b004SRick Macklem int xfer, left, len;
656ae070589SRick Macklem struct mbuf *mp;
6579ec7b004SRick Macklem long uiosiz, rem;
6589ec7b004SRick Macklem int error = 0;
6599ec7b004SRick Macklem
6609ec7b004SRick Macklem mp = nd->nd_md;
6619ec7b004SRick Macklem mbufcp = nd->nd_dpos;
662c948a17aSRick Macklem len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
6639ec7b004SRick Macklem rem = NFSM_RNDUP(siz) - siz;
6649ec7b004SRick Macklem while (siz > 0) {
665a9285ae5SZack Kirsch if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
666a9285ae5SZack Kirsch error = EBADRPC;
667a9285ae5SZack Kirsch goto out;
668a9285ae5SZack Kirsch }
6699ec7b004SRick Macklem left = uiop->uio_iov->iov_len;
6709ec7b004SRick Macklem uiocp = uiop->uio_iov->iov_base;
6719ec7b004SRick Macklem if (left > siz)
6729ec7b004SRick Macklem left = siz;
6739ec7b004SRick Macklem uiosiz = left;
6749ec7b004SRick Macklem while (left > 0) {
6759ec7b004SRick Macklem while (len == 0) {
676c948a17aSRick Macklem mp = mp->m_next;
677a9285ae5SZack Kirsch if (mp == NULL) {
678a9285ae5SZack Kirsch error = EBADRPC;
679a9285ae5SZack Kirsch goto out;
680a9285ae5SZack Kirsch }
681c948a17aSRick Macklem mbufcp = mtod(mp, caddr_t);
682c948a17aSRick Macklem len = mp->m_len;
6836d659a5dSBenno Rice KASSERT(len >= 0,
6846d659a5dSBenno Rice ("len %d, corrupted mbuf?", len));
6859ec7b004SRick Macklem }
6869ec7b004SRick Macklem xfer = (left > len) ? len : left;
6879ec7b004SRick Macklem if (uiop->uio_segflg == UIO_SYSSPACE)
6889ec7b004SRick Macklem NFSBCOPY(mbufcp, uiocp, xfer);
689b484bcd5SRick Macklem else {
690b484bcd5SRick Macklem error = copyout(mbufcp, uiocp, xfer);
691b484bcd5SRick Macklem if (error != 0)
692b484bcd5SRick Macklem goto out;
693b484bcd5SRick Macklem }
6949ec7b004SRick Macklem left -= xfer;
6959ec7b004SRick Macklem len -= xfer;
6969ec7b004SRick Macklem mbufcp += xfer;
6979ec7b004SRick Macklem uiocp += xfer;
6989ec7b004SRick Macklem uiop->uio_offset += xfer;
6999ec7b004SRick Macklem uiop->uio_resid -= xfer;
7009ec7b004SRick Macklem }
7019ec7b004SRick Macklem if (uiop->uio_iov->iov_len <= siz) {
7029ec7b004SRick Macklem uiop->uio_iovcnt--;
7039ec7b004SRick Macklem uiop->uio_iov++;
7049ec7b004SRick Macklem } else {
7059ec7b004SRick Macklem uiop->uio_iov->iov_base = (void *)
7069ec7b004SRick Macklem ((char *)uiop->uio_iov->iov_base + uiosiz);
7079ec7b004SRick Macklem uiop->uio_iov->iov_len -= uiosiz;
7089ec7b004SRick Macklem }
7099ec7b004SRick Macklem siz -= uiosiz;
7109ec7b004SRick Macklem }
7119ec7b004SRick Macklem nd->nd_dpos = mbufcp;
7129ec7b004SRick Macklem nd->nd_md = mp;
7139ec7b004SRick Macklem if (rem > 0) {
7149ec7b004SRick Macklem if (len < rem)
7159ec7b004SRick Macklem error = nfsm_advance(nd, rem, len);
7169ec7b004SRick Macklem else
7179ec7b004SRick Macklem nd->nd_dpos += rem;
7189ec7b004SRick Macklem }
719a9285ae5SZack Kirsch
720a9285ae5SZack Kirsch out:
721a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
7229ec7b004SRick Macklem return (error);
7239ec7b004SRick Macklem }
7249ec7b004SRick Macklem
7259ec7b004SRick Macklem /*
7269ec7b004SRick Macklem * Help break down an mbuf chain by setting the first siz bytes contiguous
7279ec7b004SRick Macklem * pointed to by returned val.
7289ec7b004SRick Macklem * This is used by the macro NFSM_DISSECT for tough
7299ec7b004SRick Macklem * cases.
7309ec7b004SRick Macklem */
731b9cc3262SRyan Moeller void *
nfsm_dissct(struct nfsrv_descript * nd,int siz,int how)732d96b98a3SKenneth D. Merry nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
7339ec7b004SRick Macklem {
734ae070589SRick Macklem struct mbuf *mp2;
7359ec7b004SRick Macklem int siz2, xfer;
7369ec7b004SRick Macklem caddr_t p;
7379ec7b004SRick Macklem int left;
7389ec7b004SRick Macklem caddr_t retp;
7399ec7b004SRick Macklem
7409ec7b004SRick Macklem retp = NULL;
7413973ef1dSRick Macklem left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
7429ec7b004SRick Macklem while (left == 0) {
7433973ef1dSRick Macklem nd->nd_md = nd->nd_md->m_next;
7443973ef1dSRick Macklem if (nd->nd_md == NULL)
7453973ef1dSRick Macklem return (retp);
7463973ef1dSRick Macklem left = nd->nd_md->m_len;
7473973ef1dSRick Macklem nd->nd_dpos = mtod(nd->nd_md, caddr_t);
7489ec7b004SRick Macklem }
7499ec7b004SRick Macklem if (left >= siz) {
7509ec7b004SRick Macklem retp = nd->nd_dpos;
7519ec7b004SRick Macklem nd->nd_dpos += siz;
7523973ef1dSRick Macklem } else if (nd->nd_md->m_next == NULL) {
7533973ef1dSRick Macklem return (retp);
7549ec7b004SRick Macklem } else if (siz > ncl_mbuf_mhlen) {
7559ec7b004SRick Macklem panic("nfs S too big");
7569ec7b004SRick Macklem } else {
7578b43388cSZhenlei Huang MGET(mp2, how, MT_DATA);
758d96b98a3SKenneth D. Merry if (mp2 == NULL)
759d96b98a3SKenneth D. Merry return (NULL);
760c948a17aSRick Macklem mp2->m_next = nd->nd_md->m_next;
761c948a17aSRick Macklem nd->nd_md->m_next = mp2;
762c948a17aSRick Macklem nd->nd_md->m_len -= left;
7633973ef1dSRick Macklem nd->nd_md = mp2;
7643973ef1dSRick Macklem retp = p = mtod(mp2, caddr_t);
7653973ef1dSRick Macklem NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
7669ec7b004SRick Macklem siz2 = siz - left;
7679ec7b004SRick Macklem p += left;
7683973ef1dSRick Macklem mp2 = mp2->m_next;
7699ec7b004SRick Macklem /* Loop around copying up the siz2 bytes */
7709ec7b004SRick Macklem while (siz2 > 0) {
7713973ef1dSRick Macklem if (mp2 == NULL)
7729ec7b004SRick Macklem return (NULL);
7733973ef1dSRick Macklem xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
7743973ef1dSRick Macklem if (xfer > 0) {
7753973ef1dSRick Macklem NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
7763973ef1dSRick Macklem mp2->m_data += xfer;
7773973ef1dSRick Macklem mp2->m_len -= xfer;
7789ec7b004SRick Macklem p += xfer;
7799ec7b004SRick Macklem siz2 -= xfer;
7809ec7b004SRick Macklem }
7813973ef1dSRick Macklem if (siz2 > 0)
7823973ef1dSRick Macklem mp2 = mp2->m_next;
7833973ef1dSRick Macklem }
7843973ef1dSRick Macklem nd->nd_md->m_len = siz;
7853973ef1dSRick Macklem nd->nd_md = mp2;
7863973ef1dSRick Macklem nd->nd_dpos = mtod(mp2, caddr_t);
7879ec7b004SRick Macklem }
7889ec7b004SRick Macklem return (retp);
7899ec7b004SRick Macklem }
7909ec7b004SRick Macklem
7919ec7b004SRick Macklem /*
7929ec7b004SRick Macklem * Advance the position in the mbuf chain.
7939ec7b004SRick Macklem * If offs == 0, this is a no-op, but it is simpler to just return from
7949ec7b004SRick Macklem * here than check for offs > 0 for all calls to nfsm_advance.
7959ec7b004SRick Macklem * If left == -1, it should be calculated here.
7969ec7b004SRick Macklem */
797b9cc3262SRyan Moeller int
nfsm_advance(struct nfsrv_descript * nd,int offs,int left)7989ec7b004SRick Macklem nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
7999ec7b004SRick Macklem {
800a9285ae5SZack Kirsch int error = 0;
8019ec7b004SRick Macklem
8029ec7b004SRick Macklem if (offs == 0)
803a9285ae5SZack Kirsch goto out;
8049ec7b004SRick Macklem /*
805778f2983SRick Macklem * A negative offs might indicate a corrupted mbuf chain and,
806778f2983SRick Macklem * as such, a printf is logged.
8079ec7b004SRick Macklem */
808778f2983SRick Macklem if (offs < 0) {
809778f2983SRick Macklem printf("nfsrv_advance: negative offs\n");
810778f2983SRick Macklem error = EBADRPC;
811778f2983SRick Macklem goto out;
812778f2983SRick Macklem }
8139ec7b004SRick Macklem
8149ec7b004SRick Macklem /*
8159ec7b004SRick Macklem * If left == -1, calculate it here.
8169ec7b004SRick Macklem */
8179ec7b004SRick Macklem if (left == -1)
818c948a17aSRick Macklem left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
8199ec7b004SRick Macklem nd->nd_dpos;
8209ec7b004SRick Macklem
8219ec7b004SRick Macklem /*
8229ec7b004SRick Macklem * Loop around, advancing over the mbuf data.
8239ec7b004SRick Macklem */
8249ec7b004SRick Macklem while (offs > left) {
8259ec7b004SRick Macklem offs -= left;
826c948a17aSRick Macklem nd->nd_md = nd->nd_md->m_next;
827a9285ae5SZack Kirsch if (nd->nd_md == NULL) {
828a9285ae5SZack Kirsch error = EBADRPC;
829a9285ae5SZack Kirsch goto out;
830a9285ae5SZack Kirsch }
831c948a17aSRick Macklem left = nd->nd_md->m_len;
832c948a17aSRick Macklem nd->nd_dpos = mtod(nd->nd_md, caddr_t);
8339ec7b004SRick Macklem }
8349ec7b004SRick Macklem nd->nd_dpos += offs;
835a9285ae5SZack Kirsch
836a9285ae5SZack Kirsch out:
837a9285ae5SZack Kirsch NFSEXITCODE(error);
838a9285ae5SZack Kirsch return (error);
8399ec7b004SRick Macklem }
8409ec7b004SRick Macklem
8419ec7b004SRick Macklem /*
8429ec7b004SRick Macklem * Copy a string into mbuf(s).
8439ec7b004SRick Macklem * Return the number of bytes output, including XDR overheads.
8449ec7b004SRick Macklem */
845b9cc3262SRyan Moeller int
nfsm_strtom(struct nfsrv_descript * nd,const char * cp,int siz)8469ec7b004SRick Macklem nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
8479ec7b004SRick Macklem {
848ae070589SRick Macklem struct mbuf *m2;
8499ec7b004SRick Macklem int xfer, left;
850ae070589SRick Macklem struct mbuf *m1;
8519ec7b004SRick Macklem int rem, bytesize;
8529ec7b004SRick Macklem u_int32_t *tl;
8539ec7b004SRick Macklem char *cp2;
8549ec7b004SRick Macklem
8559ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
8569ec7b004SRick Macklem *tl = txdr_unsigned(siz);
8579ec7b004SRick Macklem rem = NFSM_RNDUP(siz) - siz;
8589ec7b004SRick Macklem bytesize = NFSX_UNSIGNED + siz + rem;
8599ec7b004SRick Macklem m2 = nd->nd_mb;
8609ec7b004SRick Macklem cp2 = nd->nd_bpos;
86134fc29e0SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0)
86234fc29e0SRick Macklem left = nd->nd_bextpgsiz;
86334fc29e0SRick Macklem else
8649ec7b004SRick Macklem left = M_TRAILINGSPACE(m2);
8659ec7b004SRick Macklem
86634fc29e0SRick Macklem KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
86734fc29e0SRick Macklem (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
86834fc29e0SRick Macklem ((m2->m_flags & (M_EXT | M_EXTPG)) !=
86934fc29e0SRick Macklem (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
87034fc29e0SRick Macklem ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
8719ec7b004SRick Macklem /*
8729ec7b004SRick Macklem * Loop around copying the string to mbuf(s).
8739ec7b004SRick Macklem */
8749ec7b004SRick Macklem while (siz > 0) {
8759ec7b004SRick Macklem if (left == 0) {
87634fc29e0SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0) {
87734fc29e0SRick Macklem m2 = nfsm_add_ext_pgs(m2,
87834fc29e0SRick Macklem nd->nd_maxextsiz, &nd->nd_bextpg);
87934fc29e0SRick Macklem cp2 = (char *)(void *)PHYS_TO_DMAP(
88034fc29e0SRick Macklem m2->m_epg_pa[nd->nd_bextpg]);
88134fc29e0SRick Macklem nd->nd_bextpgsiz = left = PAGE_SIZE;
88234fc29e0SRick Macklem } else {
8839ec7b004SRick Macklem if (siz > ncl_mbuf_mlen)
884eb1b1807SGleb Smirnoff NFSMCLGET(m1, M_WAITOK);
8859ec7b004SRick Macklem else
8869ec7b004SRick Macklem NFSMGET(m1);
887c948a17aSRick Macklem m1->m_len = 0;
88834fc29e0SRick Macklem cp2 = mtod(m1, char *);
88934fc29e0SRick Macklem left = M_TRAILINGSPACE(m1);
890c948a17aSRick Macklem m2->m_next = m1;
8919ec7b004SRick Macklem m2 = m1;
89234fc29e0SRick Macklem }
8939ec7b004SRick Macklem }
8949ec7b004SRick Macklem if (left >= siz)
8959ec7b004SRick Macklem xfer = siz;
8969ec7b004SRick Macklem else
8979ec7b004SRick Macklem xfer = left;
8989ec7b004SRick Macklem NFSBCOPY(cp, cp2, xfer);
8999ec7b004SRick Macklem cp += xfer;
90034fc29e0SRick Macklem cp2 += xfer;
901c948a17aSRick Macklem m2->m_len += xfer;
9029ec7b004SRick Macklem siz -= xfer;
9039ec7b004SRick Macklem left -= xfer;
90434fc29e0SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0) {
90534fc29e0SRick Macklem nd->nd_bextpgsiz -= xfer;
90634fc29e0SRick Macklem m2->m_epg_last_len += xfer;
90734fc29e0SRick Macklem }
9089ec7b004SRick Macklem if (siz == 0 && rem) {
9099ec7b004SRick Macklem if (left < rem)
9109ec7b004SRick Macklem panic("nfsm_strtom");
91134fc29e0SRick Macklem NFSBZERO(cp2, rem);
912c948a17aSRick Macklem m2->m_len += rem;
91334fc29e0SRick Macklem cp2 += rem;
91434fc29e0SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0) {
91534fc29e0SRick Macklem nd->nd_bextpgsiz -= rem;
91634fc29e0SRick Macklem m2->m_epg_last_len += rem;
91734fc29e0SRick Macklem }
9189ec7b004SRick Macklem }
9199ec7b004SRick Macklem }
9209ec7b004SRick Macklem nd->nd_mb = m2;
92134fc29e0SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0)
92234fc29e0SRick Macklem nd->nd_bpos = cp2;
92334fc29e0SRick Macklem else
92434fc29e0SRick Macklem nd->nd_bpos = mtod(m2, char *) + m2->m_len;
9259ec7b004SRick Macklem return (bytesize);
9269ec7b004SRick Macklem }
9279ec7b004SRick Macklem
9289ec7b004SRick Macklem /*
9299ec7b004SRick Macklem * Called once to initialize data structures...
9309ec7b004SRick Macklem */
931b9cc3262SRyan Moeller void
newnfs_init(void)9329ec7b004SRick Macklem newnfs_init(void)
9339ec7b004SRick Macklem {
9349ec7b004SRick Macklem static int nfs_inited = 0;
9359ec7b004SRick Macklem
9369ec7b004SRick Macklem if (nfs_inited)
9379ec7b004SRick Macklem return;
9389ec7b004SRick Macklem nfs_inited = 1;
9399ec7b004SRick Macklem
9409ec7b004SRick Macklem newnfs_true = txdr_unsigned(TRUE);
9419ec7b004SRick Macklem newnfs_false = txdr_unsigned(FALSE);
9429ec7b004SRick Macklem newnfs_xdrneg1 = txdr_unsigned(-1);
9439ec7b004SRick Macklem nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
9449ec7b004SRick Macklem if (nfscl_ticks < 1)
9459ec7b004SRick Macklem nfscl_ticks = 1;
9469ec7b004SRick Macklem NFSSETBOOTTIME(nfsboottime);
9479ec7b004SRick Macklem
9489ec7b004SRick Macklem /*
9499ec7b004SRick Macklem * Initialize reply list and start timer
9509ec7b004SRick Macklem */
9519ec7b004SRick Macklem TAILQ_INIT(&nfsd_reqq);
9529ec7b004SRick Macklem }
9539ec7b004SRick Macklem
9549ec7b004SRick Macklem /*
9559ec7b004SRick Macklem * Put a file handle in an mbuf list.
9569ec7b004SRick Macklem * If the size argument == 0, just use the default size.
9579ec7b004SRick Macklem * set_true == 1 if there should be an newnfs_true prepended on the file handle.
9589ec7b004SRick Macklem * Return the number of bytes output, including XDR overhead.
9599ec7b004SRick Macklem */
960b9cc3262SRyan Moeller int
nfsm_fhtom(struct nfsmount * nmp,struct nfsrv_descript * nd,u_int8_t * fhp,int size,int set_true)961896516e5SRick Macklem nfsm_fhtom(struct nfsmount *nmp, struct nfsrv_descript *nd, u_int8_t *fhp,
962896516e5SRick Macklem int size, int set_true)
9639ec7b004SRick Macklem {
9649ec7b004SRick Macklem u_int32_t *tl;
9659ec7b004SRick Macklem u_int8_t *cp;
966638b90a1SRick Macklem int fullsiz, bytesize = 0;
9679ec7b004SRick Macklem
968896516e5SRick Macklem KASSERT(nmp == NULL || nmp->nm_fhsize > 0,
969896516e5SRick Macklem ("nfsm_fhtom: 0 length fh"));
9709ec7b004SRick Macklem if (size == 0)
9719ec7b004SRick Macklem size = NFSX_MYFH;
9729ec7b004SRick Macklem switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
9739ec7b004SRick Macklem case ND_NFSV2:
9749ec7b004SRick Macklem if (size > NFSX_V2FH)
9759ec7b004SRick Macklem panic("fh size > NFSX_V2FH for NFSv2");
9769ec7b004SRick Macklem NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
9779ec7b004SRick Macklem NFSBCOPY(fhp, cp, size);
9789ec7b004SRick Macklem if (size < NFSX_V2FH)
9799ec7b004SRick Macklem NFSBZERO(cp + size, NFSX_V2FH - size);
9809ec7b004SRick Macklem bytesize = NFSX_V2FH;
9819ec7b004SRick Macklem break;
9829ec7b004SRick Macklem case ND_NFSV3:
9839ec7b004SRick Macklem case ND_NFSV4:
984896516e5SRick Macklem if (size == NFSX_FHMAX + 1 && nmp != NULL &&
985896516e5SRick Macklem (nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
986896516e5SRick Macklem fhp = nmp->nm_fh;
987896516e5SRick Macklem size = nmp->nm_fhsize;
988896516e5SRick Macklem }
9899ec7b004SRick Macklem fullsiz = NFSM_RNDUP(size);
9909ec7b004SRick Macklem if (set_true) {
9919ec7b004SRick Macklem bytesize = 2 * NFSX_UNSIGNED + fullsiz;
9929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
9939ec7b004SRick Macklem *tl = newnfs_true;
9949ec7b004SRick Macklem } else {
9959ec7b004SRick Macklem bytesize = NFSX_UNSIGNED + fullsiz;
9969ec7b004SRick Macklem }
9979ec7b004SRick Macklem (void) nfsm_strtom(nd, fhp, size);
9989ec7b004SRick Macklem break;
99974b8d63dSPedro F. Giffuni }
10009ec7b004SRick Macklem return (bytesize);
10019ec7b004SRick Macklem }
10029ec7b004SRick Macklem
10039ec7b004SRick Macklem /*
10049ec7b004SRick Macklem * This function compares two net addresses by family and returns TRUE
10059ec7b004SRick Macklem * if they are the same host.
10069ec7b004SRick Macklem * If there is any doubt, return FALSE.
10079ec7b004SRick Macklem * The AF_INET family is handled as a special case so that address mbufs
10089ec7b004SRick Macklem * don't need to be saved to store "struct in_addr", which is only 4 bytes.
10099ec7b004SRick Macklem */
1010b9cc3262SRyan Moeller int
nfsaddr_match(int family,union nethostaddr * haddr,NFSSOCKADDR_T nam)10119ec7b004SRick Macklem nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
10129ec7b004SRick Macklem {
1013a6f77c9aSRick Macklem #ifdef INET
10149ec7b004SRick Macklem struct sockaddr_in *inetaddr;
1015a6f77c9aSRick Macklem #endif
10169ec7b004SRick Macklem
10179ec7b004SRick Macklem switch (family) {
1018a6f77c9aSRick Macklem #ifdef INET
10199ec7b004SRick Macklem case AF_INET:
10209ec7b004SRick Macklem inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
10219ec7b004SRick Macklem if (inetaddr->sin_family == AF_INET &&
10229ec7b004SRick Macklem inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
10239ec7b004SRick Macklem return (1);
10249ec7b004SRick Macklem break;
1025a6f77c9aSRick Macklem #endif
10269ec7b004SRick Macklem #ifdef INET6
10279ec7b004SRick Macklem case AF_INET6:
10289ec7b004SRick Macklem {
10299ec7b004SRick Macklem struct sockaddr_in6 *inetaddr6;
10309ec7b004SRick Macklem
10319ec7b004SRick Macklem inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
10329ec7b004SRick Macklem /* XXX - should test sin6_scope_id ? */
10339ec7b004SRick Macklem if (inetaddr6->sin6_family == AF_INET6 &&
10349ec7b004SRick Macklem IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
10359ec7b004SRick Macklem &haddr->had_inet6))
10369ec7b004SRick Macklem return (1);
10379ec7b004SRick Macklem }
10389ec7b004SRick Macklem break;
10399ec7b004SRick Macklem #endif
104074b8d63dSPedro F. Giffuni }
10419ec7b004SRick Macklem return (0);
10429ec7b004SRick Macklem }
10439ec7b004SRick Macklem
10449ec7b004SRick Macklem /*
10459ec7b004SRick Macklem * Similar to the above, but takes to NFSSOCKADDR_T args.
10469ec7b004SRick Macklem */
1047b9cc3262SRyan Moeller int
nfsaddr2_match(NFSSOCKADDR_T nam1,NFSSOCKADDR_T nam2)10489ec7b004SRick Macklem nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
10499ec7b004SRick Macklem {
10509ec7b004SRick Macklem struct sockaddr_in *addr1, *addr2;
10519ec7b004SRick Macklem struct sockaddr *inaddr;
10529ec7b004SRick Macklem
10539ec7b004SRick Macklem inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
10549ec7b004SRick Macklem switch (inaddr->sa_family) {
10559ec7b004SRick Macklem case AF_INET:
10569ec7b004SRick Macklem addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
10579ec7b004SRick Macklem addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
10589ec7b004SRick Macklem if (addr2->sin_family == AF_INET &&
10599ec7b004SRick Macklem addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
10609ec7b004SRick Macklem return (1);
10619ec7b004SRick Macklem break;
10629ec7b004SRick Macklem #ifdef INET6
10639ec7b004SRick Macklem case AF_INET6:
10649ec7b004SRick Macklem {
10659ec7b004SRick Macklem struct sockaddr_in6 *inet6addr1, *inet6addr2;
10669ec7b004SRick Macklem
10679ec7b004SRick Macklem inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
10689ec7b004SRick Macklem inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
10699ec7b004SRick Macklem /* XXX - should test sin6_scope_id ? */
10709ec7b004SRick Macklem if (inet6addr2->sin6_family == AF_INET6 &&
10719ec7b004SRick Macklem IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
10729ec7b004SRick Macklem &inet6addr2->sin6_addr))
10739ec7b004SRick Macklem return (1);
10749ec7b004SRick Macklem }
10759ec7b004SRick Macklem break;
10769ec7b004SRick Macklem #endif
107774b8d63dSPedro F. Giffuni }
10789ec7b004SRick Macklem return (0);
10799ec7b004SRick Macklem }
10809ec7b004SRick Macklem
10819ec7b004SRick Macklem /*
10829ec7b004SRick Macklem * Dissect a file handle on the client.
10839ec7b004SRick Macklem */
1084b9cc3262SRyan Moeller int
nfsm_getfh(struct nfsrv_descript * nd,struct nfsfh ** nfhpp)10859ec7b004SRick Macklem nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
10869ec7b004SRick Macklem {
10879ec7b004SRick Macklem u_int32_t *tl;
10889ec7b004SRick Macklem struct nfsfh *nfhp;
10899ec7b004SRick Macklem int error, len;
10909ec7b004SRick Macklem
10919ec7b004SRick Macklem *nfhpp = NULL;
10929ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
10939ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
10949ec7b004SRick Macklem if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1095a9285ae5SZack Kirsch len > NFSX_FHMAX) {
1096a9285ae5SZack Kirsch error = EBADRPC;
1097a9285ae5SZack Kirsch goto nfsmout;
1098a9285ae5SZack Kirsch }
10999ec7b004SRick Macklem } else
11009ec7b004SRick Macklem len = NFSX_V2FH;
1101222daa42SConrad Meyer nfhp = malloc(sizeof (struct nfsfh) + len,
11029ec7b004SRick Macklem M_NFSFH, M_WAITOK);
11039ec7b004SRick Macklem error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
11049ec7b004SRick Macklem if (error) {
1105222daa42SConrad Meyer free(nfhp, M_NFSFH);
1106a9285ae5SZack Kirsch goto nfsmout;
11079ec7b004SRick Macklem }
11089ec7b004SRick Macklem nfhp->nfh_len = len;
11099ec7b004SRick Macklem *nfhpp = nfhp;
11109ec7b004SRick Macklem nfsmout:
1111a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
11129ec7b004SRick Macklem return (error);
11139ec7b004SRick Macklem }
11149ec7b004SRick Macklem
11159ec7b004SRick Macklem /*
11169ec7b004SRick Macklem * Break down the nfsv4 acl.
11179ec7b004SRick Macklem * If the aclp == NULL or won't fit in an acl, just discard the acl info.
11189ec7b004SRick Macklem */
1119b9cc3262SRyan Moeller int
nfsrv_dissectacl(struct nfsrv_descript * nd,NFSACL_T * aclp,bool server,int * aclerrp,int * aclsizep,__unused NFSPROC_T * p)1120a91a5784SRick Macklem nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server,
1121a91a5784SRick Macklem int *aclerrp, int *aclsizep, __unused NFSPROC_T *p)
11229ec7b004SRick Macklem {
11239ec7b004SRick Macklem u_int32_t *tl;
11249ec7b004SRick Macklem int i, aclsize;
11259ec7b004SRick Macklem int acecnt, error = 0, aceerr = 0, acesize;
11269ec7b004SRick Macklem
11279ec7b004SRick Macklem *aclerrp = 0;
11289ec7b004SRick Macklem if (aclp)
11299ec7b004SRick Macklem aclp->acl_cnt = 0;
11309ec7b004SRick Macklem /*
11319ec7b004SRick Macklem * Parse out the ace entries and expect them to conform to
11329ec7b004SRick Macklem * what can be supported by R/W/X bits.
11339ec7b004SRick Macklem */
11349ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11359ec7b004SRick Macklem aclsize = NFSX_UNSIGNED;
11369ec7b004SRick Macklem acecnt = fxdr_unsigned(int, *tl);
1137db0ac6deSCy Schubert /*
1138db0ac6deSCy Schubert * The RFCs do not define a fixed limit to the number of ACEs in
1139db0ac6deSCy Schubert * an ACL, but 10240 should be more than sufficient.
1140db0ac6deSCy Schubert */
1141db0ac6deSCy Schubert if (acecnt < 0 || acecnt > 10240) {
1142db0ac6deSCy Schubert error = NFSERR_BADXDR;
1143db0ac6deSCy Schubert goto nfsmout;
1144db0ac6deSCy Schubert }
11459ec7b004SRick Macklem if (acecnt > ACL_MAX_ENTRIES)
1146b008a72cSZack Kirsch aceerr = NFSERR_ATTRNOTSUPP;
11479ec7b004SRick Macklem if (nfsrv_useacl == 0)
1148b008a72cSZack Kirsch aceerr = NFSERR_ATTRNOTSUPP;
11499ec7b004SRick Macklem for (i = 0; i < acecnt; i++) {
11509ec7b004SRick Macklem if (aclp && !aceerr)
11519ec7b004SRick Macklem error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1152a91a5784SRick Macklem server, &aceerr, &acesize, p);
11539ec7b004SRick Macklem else
11549ec7b004SRick Macklem error = nfsrv_skipace(nd, &acesize);
11559ec7b004SRick Macklem if (error)
1156a9285ae5SZack Kirsch goto nfsmout;
11579ec7b004SRick Macklem aclsize += acesize;
11589ec7b004SRick Macklem }
11599ec7b004SRick Macklem if (aclp && !aceerr)
11609ec7b004SRick Macklem aclp->acl_cnt = acecnt;
11619ec7b004SRick Macklem if (aceerr)
11629ec7b004SRick Macklem *aclerrp = aceerr;
11639ec7b004SRick Macklem if (aclsizep)
11649ec7b004SRick Macklem *aclsizep = aclsize;
11659ec7b004SRick Macklem nfsmout:
1166a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
11679ec7b004SRick Macklem return (error);
11689ec7b004SRick Macklem }
11699ec7b004SRick Macklem
11709ec7b004SRick Macklem /*
11719ec7b004SRick Macklem * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
11729ec7b004SRick Macklem */
11739ec7b004SRick Macklem static int
nfsrv_skipace(struct nfsrv_descript * nd,int * acesizep)11749ec7b004SRick Macklem nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
11759ec7b004SRick Macklem {
11769ec7b004SRick Macklem u_int32_t *tl;
11779ec7b004SRick Macklem int error, len = 0;
11789ec7b004SRick Macklem
11799ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
11809ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 3));
11819ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
11829ec7b004SRick Macklem nfsmout:
11839ec7b004SRick Macklem *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1184a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
11859ec7b004SRick Macklem return (error);
11869ec7b004SRick Macklem }
11879ec7b004SRick Macklem
11889ec7b004SRick Macklem /*
11899ec7b004SRick Macklem * Get attribute bits from an mbuf list.
11909ec7b004SRick Macklem * Returns EBADRPC for a parsing error, 0 otherwise.
11919ec7b004SRick Macklem * If the clearinvalid flag is set, clear the bits not supported.
11929ec7b004SRick Macklem */
1193b9cc3262SRyan Moeller int
nfsrv_getattrbits(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp,int * cntp,int * retnotsupp)11949ec7b004SRick Macklem nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
11959ec7b004SRick Macklem int *retnotsupp)
11969ec7b004SRick Macklem {
11979ec7b004SRick Macklem u_int32_t *tl;
11989ec7b004SRick Macklem int cnt, i, outcnt;
11999ec7b004SRick Macklem int error = 0;
12009ec7b004SRick Macklem
12019ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
12029ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl);
1203a9285ae5SZack Kirsch if (cnt < 0) {
1204a9285ae5SZack Kirsch error = NFSERR_BADXDR;
1205a9285ae5SZack Kirsch goto nfsmout;
1206a9285ae5SZack Kirsch }
1207a36b76a7SRick Macklem if (cnt > NFSATTRBIT_MAXWORDS)
12089ec7b004SRick Macklem outcnt = NFSATTRBIT_MAXWORDS;
1209a36b76a7SRick Macklem else
12109ec7b004SRick Macklem outcnt = cnt;
12119ec7b004SRick Macklem NFSZERO_ATTRBIT(attrbitp);
12129ec7b004SRick Macklem if (outcnt > 0) {
12139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
12149ec7b004SRick Macklem for (i = 0; i < outcnt; i++)
12159ec7b004SRick Macklem attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
12169ec7b004SRick Macklem }
1217a36b76a7SRick Macklem for (i = 0; i < (cnt - outcnt); i++) {
1218a36b76a7SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1219a36b76a7SRick Macklem if (retnotsupp != NULL && *tl != 0)
1220a36b76a7SRick Macklem *retnotsupp = NFSERR_ATTRNOTSUPP;
1221a36b76a7SRick Macklem }
12229ec7b004SRick Macklem if (cntp)
12239ec7b004SRick Macklem *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
12249ec7b004SRick Macklem nfsmout:
1225a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
12269ec7b004SRick Macklem return (error);
12279ec7b004SRick Macklem }
12289ec7b004SRick Macklem
12299ec7b004SRick Macklem /*
1230f4179ad4SRick Macklem * Get operation bits from an mbuf list.
1231f4179ad4SRick Macklem * Returns EBADRPC for a parsing error, 0 otherwise.
1232f4179ad4SRick Macklem */
1233f4179ad4SRick Macklem int
nfsrv_getopbits(struct nfsrv_descript * nd,nfsopbit_t * opbitp,int * cntp)1234f4179ad4SRick Macklem nfsrv_getopbits(struct nfsrv_descript *nd, nfsopbit_t *opbitp, int *cntp)
1235f4179ad4SRick Macklem {
1236f4179ad4SRick Macklem uint32_t *tl;
1237f4179ad4SRick Macklem int cnt, i, outcnt;
1238f4179ad4SRick Macklem int error = 0;
1239f4179ad4SRick Macklem
1240f4179ad4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1241f4179ad4SRick Macklem cnt = fxdr_unsigned(int, *tl);
1242f4179ad4SRick Macklem if (cnt < 0) {
1243f4179ad4SRick Macklem error = NFSERR_BADXDR;
1244f4179ad4SRick Macklem goto nfsmout;
1245f4179ad4SRick Macklem }
1246f4179ad4SRick Macklem if (cnt > NFSOPBIT_MAXWORDS)
1247f4179ad4SRick Macklem outcnt = NFSOPBIT_MAXWORDS;
1248f4179ad4SRick Macklem else
1249f4179ad4SRick Macklem outcnt = cnt;
1250f4179ad4SRick Macklem NFSZERO_OPBIT(opbitp);
1251f4179ad4SRick Macklem if (outcnt > 0) {
1252f4179ad4SRick Macklem NFSM_DISSECT(tl, uint32_t *, outcnt * NFSX_UNSIGNED);
1253f4179ad4SRick Macklem for (i = 0; i < outcnt; i++)
1254f4179ad4SRick Macklem opbitp->bits[i] = fxdr_unsigned(uint32_t, *tl++);
1255f4179ad4SRick Macklem }
1256f4179ad4SRick Macklem for (i = 0; i < (cnt - outcnt); i++) {
1257f4179ad4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1258f4179ad4SRick Macklem if (*tl != 0) {
1259f4179ad4SRick Macklem error = NFSERR_BADXDR;
1260f4179ad4SRick Macklem goto nfsmout;
1261f4179ad4SRick Macklem }
1262f4179ad4SRick Macklem }
1263f4179ad4SRick Macklem if (cntp != NULL)
1264f4179ad4SRick Macklem *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1265f4179ad4SRick Macklem nfsmout:
1266f4179ad4SRick Macklem NFSEXITCODE2(error, nd);
1267f4179ad4SRick Macklem return (error);
1268f4179ad4SRick Macklem }
1269f4179ad4SRick Macklem
1270f4179ad4SRick Macklem /*
12719ec7b004SRick Macklem * Get the attributes for V4.
12729ec7b004SRick Macklem * If the compare flag is true, test for any attribute changes,
12739ec7b004SRick Macklem * otherwise return the attribute values.
12749ec7b004SRick Macklem * These attributes cover fields in "struct vattr", "struct statfs",
12759ec7b004SRick Macklem * "struct nfsfsinfo", the file handle and the lease duration.
12769ec7b004SRick Macklem * The value of retcmpp is set to 1 if all attributes are the same,
12779ec7b004SRick Macklem * and 0 otherwise.
12789ec7b004SRick Macklem * Returns EBADRPC if it can't be parsed, 0 otherwise.
12799ec7b004SRick Macklem */
1280b9cc3262SRyan Moeller int
nfsv4_loadattr(struct nfsrv_descript * nd,vnode_t vp,struct nfsvattr * nap,struct nfsfh ** nfhpp,fhandle_t * fhp,int fhsize,struct nfsv3_pathconf * pc,struct statfs * sbp,struct nfsstatfs * sfp,struct nfsfsinfo * fsp,NFSACL_T * aclp,int compare,int * retcmpp,u_int32_t * leasep,u_int32_t * rderrp,NFSPROC_T * p,struct ucred * cred)12819ec7b004SRick Macklem nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
12829ec7b004SRick Macklem struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
12839ec7b004SRick Macklem struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
12849ec7b004SRick Macklem struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
12859ec7b004SRick Macklem u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
12869ec7b004SRick Macklem {
12879ec7b004SRick Macklem u_int32_t *tl;
1288a9285ae5SZack Kirsch int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
12899ec7b004SRick Macklem int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
12909ec7b004SRick Macklem u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
12919ec7b004SRick Macklem nfsattrbit_t attrbits, retattrbits, checkattrbits;
12929ec7b004SRick Macklem struct nfsfh *tnfhp;
12939ec7b004SRick Macklem struct nfsreferral *refp;
12949ec7b004SRick Macklem u_quad_t tquad;
12959ec7b004SRick Macklem nfsquad_t tnfsquad;
12969ec7b004SRick Macklem struct timespec temptime;
12979ec7b004SRick Macklem uid_t uid;
12989ec7b004SRick Macklem gid_t gid;
12999ec7b004SRick Macklem u_int32_t freenum = 0, tuint;
13009ec7b004SRick Macklem u_int64_t uquad = 0, thyp, thyp2;
13019ec7b004SRick Macklem #ifdef QUOTA
13029ec7b004SRick Macklem struct dqblk dqb;
13039ec7b004SRick Macklem uid_t savuid;
13049ec7b004SRick Macklem #endif
130563659ba6SColin Percival
130695ac7f1aSRick Macklem CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1307f0db2b60SRick Macklem NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
13089ec7b004SRick Macklem if (compare) {
13099ec7b004SRick Macklem retnotsup = 0;
13109ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
13119ec7b004SRick Macklem } else {
13129ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
13139ec7b004SRick Macklem }
13149ec7b004SRick Macklem if (error)
1315a9285ae5SZack Kirsch goto nfsmout;
13169ec7b004SRick Macklem
13179ec7b004SRick Macklem if (compare) {
13189ec7b004SRick Macklem *retcmpp = retnotsup;
13199ec7b004SRick Macklem } else {
13209ec7b004SRick Macklem /*
13219ec7b004SRick Macklem * Just set default values to some of the important ones.
13229ec7b004SRick Macklem */
13239ec7b004SRick Macklem if (nap != NULL) {
132444328abfSAlan Somers VATTR_NULL(&nap->na_vattr);
13259ec7b004SRick Macklem nap->na_type = VREG;
13269ec7b004SRick Macklem nap->na_mode = 0;
13279ec7b004SRick Macklem nap->na_rdev = (NFSDEV_T)0;
13289ec7b004SRick Macklem nap->na_mtime.tv_sec = 0;
13299ec7b004SRick Macklem nap->na_mtime.tv_nsec = 0;
1330dd02d9d6SRick Macklem nap->na_btime.tv_sec = -1;
1331dd02d9d6SRick Macklem nap->na_btime.tv_nsec = 0;
13329ec7b004SRick Macklem nap->na_gen = 0;
13339ec7b004SRick Macklem nap->na_flags = 0;
13349ec7b004SRick Macklem nap->na_blocksize = NFS_FABLKSIZE;
13359ec7b004SRick Macklem }
13369ec7b004SRick Macklem if (sbp != NULL) {
13379ec7b004SRick Macklem sbp->f_bsize = NFS_FABLKSIZE;
13389ec7b004SRick Macklem sbp->f_blocks = 0;
13399ec7b004SRick Macklem sbp->f_bfree = 0;
13409ec7b004SRick Macklem sbp->f_bavail = 0;
13419ec7b004SRick Macklem sbp->f_files = 0;
13429ec7b004SRick Macklem sbp->f_ffree = 0;
13439ec7b004SRick Macklem }
13449ec7b004SRick Macklem if (fsp != NULL) {
13459ec7b004SRick Macklem fsp->fs_rtmax = 8192;
13469ec7b004SRick Macklem fsp->fs_rtpref = 8192;
13479ec7b004SRick Macklem fsp->fs_maxname = NFS_MAXNAMLEN;
13489ec7b004SRick Macklem fsp->fs_wtmax = 8192;
13499ec7b004SRick Macklem fsp->fs_wtpref = 8192;
13509ec7b004SRick Macklem fsp->fs_wtmult = NFS_FABLKSIZE;
13519ec7b004SRick Macklem fsp->fs_dtpref = 8192;
13529ec7b004SRick Macklem fsp->fs_maxfilesize = 0xffffffffffffffffull;
13539ec7b004SRick Macklem fsp->fs_timedelta.tv_sec = 0;
13549ec7b004SRick Macklem fsp->fs_timedelta.tv_nsec = 1;
13559ec7b004SRick Macklem fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
13569ec7b004SRick Macklem NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
13579ec7b004SRick Macklem }
13589ec7b004SRick Macklem if (pc != NULL) {
1359a0a073b1SJohn Baldwin pc->pc_linkmax = NFS_LINK_MAX;
13609ec7b004SRick Macklem pc->pc_namemax = NAME_MAX;
13619ec7b004SRick Macklem pc->pc_notrunc = 0;
13629ec7b004SRick Macklem pc->pc_chownrestricted = 0;
13639ec7b004SRick Macklem pc->pc_caseinsensitive = 0;
13649ec7b004SRick Macklem pc->pc_casepreserving = 1;
13659ec7b004SRick Macklem }
1366fb556791SRick Macklem if (sfp != NULL) {
1367fb556791SRick Macklem sfp->sf_ffiles = UINT64_MAX;
1368fb556791SRick Macklem sfp->sf_tfiles = UINT64_MAX;
1369fb556791SRick Macklem sfp->sf_afiles = UINT64_MAX;
1370fb556791SRick Macklem sfp->sf_fbytes = UINT64_MAX;
1371fb556791SRick Macklem sfp->sf_tbytes = UINT64_MAX;
1372fb556791SRick Macklem sfp->sf_abytes = UINT64_MAX;
1373fb556791SRick Macklem }
13749ec7b004SRick Macklem }
13759ec7b004SRick Macklem
13769ec7b004SRick Macklem /*
13779ec7b004SRick Macklem * Loop around getting the attributes.
13789ec7b004SRick Macklem */
13799ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
13809ec7b004SRick Macklem attrsize = fxdr_unsigned(int, *tl);
13819ec7b004SRick Macklem for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
13829ec7b004SRick Macklem if (attrsum > attrsize) {
13839ec7b004SRick Macklem error = NFSERR_BADXDR;
13849ec7b004SRick Macklem goto nfsmout;
13859ec7b004SRick Macklem }
13869ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, bitpos))
13879ec7b004SRick Macklem switch (bitpos) {
13889ec7b004SRick Macklem case NFSATTRBIT_SUPPORTEDATTRS:
13899ec7b004SRick Macklem retnotsup = 0;
13909ec7b004SRick Macklem if (compare || nap == NULL)
13919ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &retattrbits,
13929ec7b004SRick Macklem &cnt, &retnotsup);
13939ec7b004SRick Macklem else
13949ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &nap->na_suppattr,
13959ec7b004SRick Macklem &cnt, &retnotsup);
13969ec7b004SRick Macklem if (error)
1397a9285ae5SZack Kirsch goto nfsmout;
13989ec7b004SRick Macklem if (compare && !(*retcmpp)) {
1399ea5776ecSRick Macklem NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1400d8a5961fSMarcelo Araujo
1401d8a5961fSMarcelo Araujo /* Some filesystem do not support NFSv4ACL */
1402d8a5961fSMarcelo Araujo if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1403d8a5961fSMarcelo Araujo NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1404d8a5961fSMarcelo Araujo NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1405d8a5961fSMarcelo Araujo }
14069ec7b004SRick Macklem if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
14079ec7b004SRick Macklem || retnotsup)
14089ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14099ec7b004SRick Macklem }
14109ec7b004SRick Macklem attrsum += cnt;
14119ec7b004SRick Macklem break;
14129ec7b004SRick Macklem case NFSATTRBIT_TYPE:
14139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
14149ec7b004SRick Macklem if (compare) {
14159ec7b004SRick Macklem if (!(*retcmpp)) {
14169ec7b004SRick Macklem if (nap->na_type != nfsv34tov_type(*tl))
14179ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14189ec7b004SRick Macklem }
14199ec7b004SRick Macklem } else if (nap != NULL) {
14209ec7b004SRick Macklem nap->na_type = nfsv34tov_type(*tl);
14219ec7b004SRick Macklem }
14229ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
14239ec7b004SRick Macklem break;
14249ec7b004SRick Macklem case NFSATTRBIT_FHEXPIRETYPE:
14259ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
14269ec7b004SRick Macklem if (compare && !(*retcmpp)) {
14279ec7b004SRick Macklem if (fxdr_unsigned(int, *tl) !=
14289ec7b004SRick Macklem NFSV4FHTYPE_PERSISTENT)
14299ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14309ec7b004SRick Macklem }
14319ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
14329ec7b004SRick Macklem break;
14339ec7b004SRick Macklem case NFSATTRBIT_CHANGE:
14349ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
14359ec7b004SRick Macklem if (compare) {
14369ec7b004SRick Macklem if (!(*retcmpp)) {
14379ec7b004SRick Macklem if (nap->na_filerev != fxdr_hyper(tl))
14389ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14399ec7b004SRick Macklem }
14409ec7b004SRick Macklem } else if (nap != NULL) {
14419ec7b004SRick Macklem nap->na_filerev = fxdr_hyper(tl);
14429ec7b004SRick Macklem }
14439ec7b004SRick Macklem attrsum += NFSX_HYPER;
14449ec7b004SRick Macklem break;
14459ec7b004SRick Macklem case NFSATTRBIT_SIZE:
14469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
14479ec7b004SRick Macklem if (compare) {
14489ec7b004SRick Macklem if (!(*retcmpp)) {
14499ec7b004SRick Macklem if (nap->na_size != fxdr_hyper(tl))
14509ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14519ec7b004SRick Macklem }
14529ec7b004SRick Macklem } else if (nap != NULL) {
14539ec7b004SRick Macklem nap->na_size = fxdr_hyper(tl);
14549ec7b004SRick Macklem }
14559ec7b004SRick Macklem attrsum += NFSX_HYPER;
14569ec7b004SRick Macklem break;
14579ec7b004SRick Macklem case NFSATTRBIT_LINKSUPPORT:
14589ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
14599ec7b004SRick Macklem if (compare) {
14609ec7b004SRick Macklem if (!(*retcmpp)) {
14619ec7b004SRick Macklem if (fsp->fs_properties & NFSV3_FSFLINK) {
14629ec7b004SRick Macklem if (*tl == newnfs_false)
14639ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14649ec7b004SRick Macklem } else {
14659ec7b004SRick Macklem if (*tl == newnfs_true)
14669ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14679ec7b004SRick Macklem }
14689ec7b004SRick Macklem }
14699ec7b004SRick Macklem } else if (fsp != NULL) {
14709ec7b004SRick Macklem if (*tl == newnfs_true)
14719ec7b004SRick Macklem fsp->fs_properties |= NFSV3_FSFLINK;
14729ec7b004SRick Macklem else
14739ec7b004SRick Macklem fsp->fs_properties &= ~NFSV3_FSFLINK;
14749ec7b004SRick Macklem }
14759ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
14769ec7b004SRick Macklem break;
14779ec7b004SRick Macklem case NFSATTRBIT_SYMLINKSUPPORT:
14789ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
14799ec7b004SRick Macklem if (compare) {
14809ec7b004SRick Macklem if (!(*retcmpp)) {
14819ec7b004SRick Macklem if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
14829ec7b004SRick Macklem if (*tl == newnfs_false)
14839ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14849ec7b004SRick Macklem } else {
14859ec7b004SRick Macklem if (*tl == newnfs_true)
14869ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
14879ec7b004SRick Macklem }
14889ec7b004SRick Macklem }
14899ec7b004SRick Macklem } else if (fsp != NULL) {
14909ec7b004SRick Macklem if (*tl == newnfs_true)
14919ec7b004SRick Macklem fsp->fs_properties |= NFSV3_FSFSYMLINK;
14929ec7b004SRick Macklem else
14939ec7b004SRick Macklem fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
14949ec7b004SRick Macklem }
14959ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
14969ec7b004SRick Macklem break;
14979ec7b004SRick Macklem case NFSATTRBIT_NAMEDATTR:
14989ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
14999ec7b004SRick Macklem if (compare && !(*retcmpp)) {
15009ec7b004SRick Macklem if (*tl != newnfs_false)
15019ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
15029ec7b004SRick Macklem }
15039ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
15049ec7b004SRick Macklem break;
15059ec7b004SRick Macklem case NFSATTRBIT_FSID:
15069ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
15079ec7b004SRick Macklem thyp = fxdr_hyper(tl);
15089ec7b004SRick Macklem tl += 2;
15099ec7b004SRick Macklem thyp2 = fxdr_hyper(tl);
15109ec7b004SRick Macklem if (compare) {
15119ec7b004SRick Macklem if (*retcmpp == 0) {
15129ec7b004SRick Macklem if (thyp != (u_int64_t)
1513eea79fdeSAlan Somers vp->v_mount->mnt_stat.f_fsid.val[0] ||
15149ec7b004SRick Macklem thyp2 != (u_int64_t)
1515eea79fdeSAlan Somers vp->v_mount->mnt_stat.f_fsid.val[1])
15169ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
15179ec7b004SRick Macklem }
15189ec7b004SRick Macklem } else if (nap != NULL) {
15199ec7b004SRick Macklem nap->na_filesid[0] = thyp;
15209ec7b004SRick Macklem nap->na_filesid[1] = thyp2;
15219ec7b004SRick Macklem }
15229ec7b004SRick Macklem attrsum += (4 * NFSX_UNSIGNED);
15239ec7b004SRick Macklem break;
15249ec7b004SRick Macklem case NFSATTRBIT_UNIQUEHANDLES:
15259ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
15269ec7b004SRick Macklem if (compare && !(*retcmpp)) {
15279ec7b004SRick Macklem if (*tl != newnfs_true)
15289ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
15299ec7b004SRick Macklem }
15309ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
15319ec7b004SRick Macklem break;
15329ec7b004SRick Macklem case NFSATTRBIT_LEASETIME:
15339ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
15349ec7b004SRick Macklem if (compare) {
15359ec7b004SRick Macklem if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
15369ec7b004SRick Macklem !(*retcmpp))
15379ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
15389ec7b004SRick Macklem } else if (leasep != NULL) {
15399ec7b004SRick Macklem *leasep = fxdr_unsigned(u_int32_t, *tl);
15409ec7b004SRick Macklem }
15419ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
15429ec7b004SRick Macklem break;
15439ec7b004SRick Macklem case NFSATTRBIT_RDATTRERROR:
15449ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
15459ec7b004SRick Macklem if (compare) {
15469ec7b004SRick Macklem if (!(*retcmpp))
15479ec7b004SRick Macklem *retcmpp = NFSERR_INVAL;
15489ec7b004SRick Macklem } else if (rderrp != NULL) {
15499ec7b004SRick Macklem *rderrp = fxdr_unsigned(u_int32_t, *tl);
15509ec7b004SRick Macklem }
15519ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
15529ec7b004SRick Macklem break;
15539ec7b004SRick Macklem case NFSATTRBIT_ACL:
15549ec7b004SRick Macklem if (compare) {
15559ec7b004SRick Macklem if (!(*retcmpp)) {
1556d8a5961fSMarcelo Araujo if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
15579ec7b004SRick Macklem NFSACL_T *naclp;
15589ec7b004SRick Macklem
1559c3e22f83SRick Macklem naclp = acl_alloc(M_WAITOK);
1560a91a5784SRick Macklem error = nfsrv_dissectacl(nd, naclp, true,
1561a91a5784SRick Macklem &aceerr, &cnt, p);
15629ec7b004SRick Macklem if (error) {
15639ec7b004SRick Macklem acl_free(naclp);
1564a9285ae5SZack Kirsch goto nfsmout;
15659ec7b004SRick Macklem }
1566061c683cSZack Kirsch if (aceerr || aclp == NULL ||
1567061c683cSZack Kirsch nfsrv_compareacl(aclp, naclp))
15689ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
15699ec7b004SRick Macklem acl_free(naclp);
157074991298SEdward Tomasz Napierala } else {
1571a91a5784SRick Macklem error = nfsrv_dissectacl(nd, NULL, true,
1572a91a5784SRick Macklem &aceerr, &cnt, p);
1573db0ac6deSCy Schubert if (error)
1574db0ac6deSCy Schubert goto nfsmout;
15759ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
15769ec7b004SRick Macklem }
15779ec7b004SRick Macklem }
15789ec7b004SRick Macklem } else {
15799ec7b004SRick Macklem if (vp != NULL && aclp != NULL)
1580a91a5784SRick Macklem error = nfsrv_dissectacl(nd, aclp, false,
1581a91a5784SRick Macklem &aceerr, &cnt, p);
15829ec7b004SRick Macklem else
1583a91a5784SRick Macklem error = nfsrv_dissectacl(nd, NULL, false,
1584a91a5784SRick Macklem &aceerr, &cnt, p);
15859ec7b004SRick Macklem if (error)
1586a9285ae5SZack Kirsch goto nfsmout;
15879ec7b004SRick Macklem }
1588d8a5961fSMarcelo Araujo
15899ec7b004SRick Macklem attrsum += cnt;
15909ec7b004SRick Macklem break;
15919ec7b004SRick Macklem case NFSATTRBIT_ACLSUPPORT:
15929ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
15939ec7b004SRick Macklem if (compare && !(*retcmpp)) {
1594d8a5961fSMarcelo Araujo if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
15959ec7b004SRick Macklem if (fxdr_unsigned(u_int32_t, *tl) !=
15969ec7b004SRick Macklem NFSV4ACE_SUPTYPES)
15979ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
15989ec7b004SRick Macklem } else {
15999ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
16009ec7b004SRick Macklem }
16019ec7b004SRick Macklem }
16029ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
16039ec7b004SRick Macklem break;
16049ec7b004SRick Macklem case NFSATTRBIT_ARCHIVE:
16059ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
16069ec7b004SRick Macklem if (compare && !(*retcmpp))
16079ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
16089ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
16099ec7b004SRick Macklem break;
16109ec7b004SRick Macklem case NFSATTRBIT_CANSETTIME:
16119ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
16129ec7b004SRick Macklem if (compare) {
16139ec7b004SRick Macklem if (!(*retcmpp)) {
16149ec7b004SRick Macklem if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
16159ec7b004SRick Macklem if (*tl == newnfs_false)
16169ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
16179ec7b004SRick Macklem } else {
16189ec7b004SRick Macklem if (*tl == newnfs_true)
16199ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
16209ec7b004SRick Macklem }
16219ec7b004SRick Macklem }
16229ec7b004SRick Macklem } else if (fsp != NULL) {
16239ec7b004SRick Macklem if (*tl == newnfs_true)
16249ec7b004SRick Macklem fsp->fs_properties |= NFSV3_FSFCANSETTIME;
16259ec7b004SRick Macklem else
16269ec7b004SRick Macklem fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
16279ec7b004SRick Macklem }
16289ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
16299ec7b004SRick Macklem break;
16309ec7b004SRick Macklem case NFSATTRBIT_CASEINSENSITIVE:
16319ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
16329ec7b004SRick Macklem if (compare) {
16339ec7b004SRick Macklem if (!(*retcmpp)) {
16349ec7b004SRick Macklem if (*tl != newnfs_false)
16359ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
16369ec7b004SRick Macklem }
16379ec7b004SRick Macklem } else if (pc != NULL) {
16389ec7b004SRick Macklem pc->pc_caseinsensitive =
16399ec7b004SRick Macklem fxdr_unsigned(u_int32_t, *tl);
16409ec7b004SRick Macklem }
16419ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
16429ec7b004SRick Macklem break;
16439ec7b004SRick Macklem case NFSATTRBIT_CASEPRESERVING:
16449ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
16459ec7b004SRick Macklem if (compare) {
16469ec7b004SRick Macklem if (!(*retcmpp)) {
16479ec7b004SRick Macklem if (*tl != newnfs_true)
16489ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
16499ec7b004SRick Macklem }
16509ec7b004SRick Macklem } else if (pc != NULL) {
16519ec7b004SRick Macklem pc->pc_casepreserving =
16529ec7b004SRick Macklem fxdr_unsigned(u_int32_t, *tl);
16539ec7b004SRick Macklem }
16549ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
16559ec7b004SRick Macklem break;
16569ec7b004SRick Macklem case NFSATTRBIT_CHOWNRESTRICTED:
16579ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
16589ec7b004SRick Macklem if (compare) {
16599ec7b004SRick Macklem if (!(*retcmpp)) {
1660061c683cSZack Kirsch if (*tl != newnfs_true)
16619ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
16629ec7b004SRick Macklem }
16639ec7b004SRick Macklem } else if (pc != NULL) {
16649ec7b004SRick Macklem pc->pc_chownrestricted =
16659ec7b004SRick Macklem fxdr_unsigned(u_int32_t, *tl);
16669ec7b004SRick Macklem }
16679ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
16689ec7b004SRick Macklem break;
16699ec7b004SRick Macklem case NFSATTRBIT_FILEHANDLE:
16709ec7b004SRick Macklem error = nfsm_getfh(nd, &tnfhp);
16719ec7b004SRick Macklem if (error)
1672a9285ae5SZack Kirsch goto nfsmout;
16739ec7b004SRick Macklem tfhsize = tnfhp->nfh_len;
16749ec7b004SRick Macklem if (compare) {
16759ec7b004SRick Macklem if (!(*retcmpp) &&
16769ec7b004SRick Macklem !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
16779ec7b004SRick Macklem fhp, fhsize))
16789ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
1679222daa42SConrad Meyer free(tnfhp, M_NFSFH);
16809ec7b004SRick Macklem } else if (nfhpp != NULL) {
16819ec7b004SRick Macklem *nfhpp = tnfhp;
16829ec7b004SRick Macklem } else {
1683222daa42SConrad Meyer free(tnfhp, M_NFSFH);
16849ec7b004SRick Macklem }
16859ec7b004SRick Macklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
16869ec7b004SRick Macklem break;
16879ec7b004SRick Macklem case NFSATTRBIT_FILEID:
16889ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
16899ec7b004SRick Macklem thyp = fxdr_hyper(tl);
16909ec7b004SRick Macklem if (compare) {
16919ec7b004SRick Macklem if (!(*retcmpp)) {
169295ac7f1aSRick Macklem if (nap->na_fileid != thyp)
16939ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
16949ec7b004SRick Macklem }
169595ac7f1aSRick Macklem } else if (nap != NULL)
16969ec7b004SRick Macklem nap->na_fileid = thyp;
16979ec7b004SRick Macklem attrsum += NFSX_HYPER;
16989ec7b004SRick Macklem break;
16999ec7b004SRick Macklem case NFSATTRBIT_FILESAVAIL:
17009ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
17019ec7b004SRick Macklem if (compare) {
17022d90ef47SRick Macklem uquad = nfsv4_filesavail(sbp, vp->v_mount);
17032d90ef47SRick Macklem if (!(*retcmpp) && uquad != fxdr_hyper(tl))
17049ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17059ec7b004SRick Macklem } else if (sfp != NULL) {
17069ec7b004SRick Macklem sfp->sf_afiles = fxdr_hyper(tl);
17079ec7b004SRick Macklem }
17089ec7b004SRick Macklem attrsum += NFSX_HYPER;
17099ec7b004SRick Macklem break;
17109ec7b004SRick Macklem case NFSATTRBIT_FILESFREE:
17119ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
17129ec7b004SRick Macklem if (compare) {
17132d90ef47SRick Macklem uquad = (uint64_t)sbp->f_ffree;
17142d90ef47SRick Macklem if (!(*retcmpp) && uquad != fxdr_hyper(tl))
17159ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17169ec7b004SRick Macklem } else if (sfp != NULL) {
17179ec7b004SRick Macklem sfp->sf_ffiles = fxdr_hyper(tl);
17189ec7b004SRick Macklem }
17199ec7b004SRick Macklem attrsum += NFSX_HYPER;
17209ec7b004SRick Macklem break;
17219ec7b004SRick Macklem case NFSATTRBIT_FILESTOTAL:
17229ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
17239ec7b004SRick Macklem if (compare) {
17242d90ef47SRick Macklem uquad = sbp->f_files;
17252d90ef47SRick Macklem if (!(*retcmpp) && uquad != fxdr_hyper(tl))
17269ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17279ec7b004SRick Macklem } else if (sfp != NULL) {
17289ec7b004SRick Macklem sfp->sf_tfiles = fxdr_hyper(tl);
17299ec7b004SRick Macklem }
17309ec7b004SRick Macklem attrsum += NFSX_HYPER;
17319ec7b004SRick Macklem break;
17329ec7b004SRick Macklem case NFSATTRBIT_FSLOCATIONS:
17339ec7b004SRick Macklem error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
17349ec7b004SRick Macklem if (error)
1735a9285ae5SZack Kirsch goto nfsmout;
17369ec7b004SRick Macklem attrsum += l;
17379ec7b004SRick Macklem if (compare && !(*retcmpp)) {
17389ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0);
17399ec7b004SRick Macklem if (refp != NULL) {
17409ec7b004SRick Macklem if (cp == NULL || cp2 == NULL ||
17419ec7b004SRick Macklem strcmp(cp, "/") ||
17429ec7b004SRick Macklem strcmp(cp2, refp->nfr_srvlist))
17439ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17449ec7b004SRick Macklem } else if (m == 0) {
17459ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17469ec7b004SRick Macklem }
17479ec7b004SRick Macklem }
17489ec7b004SRick Macklem if (cp != NULL)
17499ec7b004SRick Macklem free(cp, M_NFSSTRING);
17509ec7b004SRick Macklem if (cp2 != NULL)
17519ec7b004SRick Macklem free(cp2, M_NFSSTRING);
17529ec7b004SRick Macklem break;
17539ec7b004SRick Macklem case NFSATTRBIT_HIDDEN:
17549ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
17559ec7b004SRick Macklem if (compare && !(*retcmpp))
17569ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
17579ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
17589ec7b004SRick Macklem break;
17599ec7b004SRick Macklem case NFSATTRBIT_HOMOGENEOUS:
17609ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
17619ec7b004SRick Macklem if (compare) {
17629ec7b004SRick Macklem if (!(*retcmpp)) {
17639ec7b004SRick Macklem if (fsp->fs_properties &
17649ec7b004SRick Macklem NFSV3_FSFHOMOGENEOUS) {
17659ec7b004SRick Macklem if (*tl == newnfs_false)
17669ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17679ec7b004SRick Macklem } else {
17689ec7b004SRick Macklem if (*tl == newnfs_true)
17699ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17709ec7b004SRick Macklem }
17719ec7b004SRick Macklem }
17729ec7b004SRick Macklem } else if (fsp != NULL) {
17739ec7b004SRick Macklem if (*tl == newnfs_true)
17749ec7b004SRick Macklem fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
17759ec7b004SRick Macklem else
17769ec7b004SRick Macklem fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
17779ec7b004SRick Macklem }
17789ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
17799ec7b004SRick Macklem break;
17809ec7b004SRick Macklem case NFSATTRBIT_MAXFILESIZE:
17819ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
17829ec7b004SRick Macklem tnfsquad.qval = fxdr_hyper(tl);
17839ec7b004SRick Macklem if (compare) {
17849ec7b004SRick Macklem if (!(*retcmpp)) {
17859ec7b004SRick Macklem tquad = NFSRV_MAXFILESIZE;
17869ec7b004SRick Macklem if (tquad != tnfsquad.qval)
17879ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
17889ec7b004SRick Macklem }
17899ec7b004SRick Macklem } else if (fsp != NULL) {
17909ec7b004SRick Macklem fsp->fs_maxfilesize = tnfsquad.qval;
17919ec7b004SRick Macklem }
17929ec7b004SRick Macklem attrsum += NFSX_HYPER;
17939ec7b004SRick Macklem break;
17949ec7b004SRick Macklem case NFSATTRBIT_MAXLINK:
17959ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
17969ec7b004SRick Macklem if (compare) {
17979ec7b004SRick Macklem if (!(*retcmpp)) {
1798a0a073b1SJohn Baldwin if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
17999ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
18009ec7b004SRick Macklem }
18019ec7b004SRick Macklem } else if (pc != NULL) {
18029ec7b004SRick Macklem pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
18039ec7b004SRick Macklem }
18049ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
18059ec7b004SRick Macklem break;
18069ec7b004SRick Macklem case NFSATTRBIT_MAXNAME:
18079ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18089ec7b004SRick Macklem if (compare) {
18099ec7b004SRick Macklem if (!(*retcmpp)) {
18109ec7b004SRick Macklem if (fsp->fs_maxname !=
18119ec7b004SRick Macklem fxdr_unsigned(u_int32_t, *tl))
18129ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
18139ec7b004SRick Macklem }
18149ec7b004SRick Macklem } else {
18159ec7b004SRick Macklem tuint = fxdr_unsigned(u_int32_t, *tl);
18169ec7b004SRick Macklem /*
18179ec7b004SRick Macklem * Some Linux NFSv4 servers report this
18189ec7b004SRick Macklem * as 0 or 4billion, so I'll set it to
18199ec7b004SRick Macklem * NFS_MAXNAMLEN. If a server actually creates
18209ec7b004SRick Macklem * a name longer than NFS_MAXNAMLEN, it will
18219ec7b004SRick Macklem * get an error back.
18229ec7b004SRick Macklem */
18239ec7b004SRick Macklem if (tuint == 0 || tuint > NFS_MAXNAMLEN)
18249ec7b004SRick Macklem tuint = NFS_MAXNAMLEN;
18259ec7b004SRick Macklem if (fsp != NULL)
18269ec7b004SRick Macklem fsp->fs_maxname = tuint;
18279ec7b004SRick Macklem if (pc != NULL)
18289ec7b004SRick Macklem pc->pc_namemax = tuint;
18299ec7b004SRick Macklem }
18309ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
18319ec7b004SRick Macklem break;
18329ec7b004SRick Macklem case NFSATTRBIT_MAXREAD:
18339ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
18349ec7b004SRick Macklem if (compare) {
18359ec7b004SRick Macklem if (!(*retcmpp)) {
18369ec7b004SRick Macklem if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
18379ec7b004SRick Macklem *(tl + 1)) || *tl != 0)
18389ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
18399ec7b004SRick Macklem }
18409ec7b004SRick Macklem } else if (fsp != NULL) {
18419ec7b004SRick Macklem fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
18429ec7b004SRick Macklem fsp->fs_rtpref = fsp->fs_rtmax;
18439ec7b004SRick Macklem fsp->fs_dtpref = fsp->fs_rtpref;
18449ec7b004SRick Macklem }
18459ec7b004SRick Macklem attrsum += NFSX_HYPER;
18469ec7b004SRick Macklem break;
18479ec7b004SRick Macklem case NFSATTRBIT_MAXWRITE:
18489ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
18499ec7b004SRick Macklem if (compare) {
18509ec7b004SRick Macklem if (!(*retcmpp)) {
18519ec7b004SRick Macklem if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
18529ec7b004SRick Macklem *(tl + 1)) || *tl != 0)
18539ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
18549ec7b004SRick Macklem }
18559ec7b004SRick Macklem } else if (fsp != NULL) {
18569ec7b004SRick Macklem fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
18579ec7b004SRick Macklem fsp->fs_wtpref = fsp->fs_wtmax;
18589ec7b004SRick Macklem }
18599ec7b004SRick Macklem attrsum += NFSX_HYPER;
18609ec7b004SRick Macklem break;
18619ec7b004SRick Macklem case NFSATTRBIT_MIMETYPE:
18629ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18639ec7b004SRick Macklem i = fxdr_unsigned(int, *tl);
18649ec7b004SRick Macklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
18659ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
18669ec7b004SRick Macklem if (error)
18679ec7b004SRick Macklem goto nfsmout;
18689ec7b004SRick Macklem if (compare && !(*retcmpp))
18699ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
18709ec7b004SRick Macklem break;
18719ec7b004SRick Macklem case NFSATTRBIT_MODE:
18729ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18739ec7b004SRick Macklem if (compare) {
18749ec7b004SRick Macklem if (!(*retcmpp)) {
18759ec7b004SRick Macklem if (nap->na_mode != nfstov_mode(*tl))
18769ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
18779ec7b004SRick Macklem }
18789ec7b004SRick Macklem } else if (nap != NULL) {
18799ec7b004SRick Macklem nap->na_mode = nfstov_mode(*tl);
18809ec7b004SRick Macklem }
18819ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
18829ec7b004SRick Macklem break;
18839ec7b004SRick Macklem case NFSATTRBIT_NOTRUNC:
18849ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18859ec7b004SRick Macklem if (compare) {
18869ec7b004SRick Macklem if (!(*retcmpp)) {
18879ec7b004SRick Macklem if (*tl != newnfs_true)
18889ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
18899ec7b004SRick Macklem }
18909ec7b004SRick Macklem } else if (pc != NULL) {
18919ec7b004SRick Macklem pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
18929ec7b004SRick Macklem }
18939ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
18949ec7b004SRick Macklem break;
18959ec7b004SRick Macklem case NFSATTRBIT_NUMLINKS:
18969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18979ec7b004SRick Macklem tuint = fxdr_unsigned(u_int32_t, *tl);
18989ec7b004SRick Macklem if (compare) {
18999ec7b004SRick Macklem if (!(*retcmpp)) {
19009ec7b004SRick Macklem if ((u_int32_t)nap->na_nlink != tuint)
19019ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
19029ec7b004SRick Macklem }
19039ec7b004SRick Macklem } else if (nap != NULL) {
19049ec7b004SRick Macklem nap->na_nlink = tuint;
19059ec7b004SRick Macklem }
19069ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
19079ec7b004SRick Macklem break;
19089ec7b004SRick Macklem case NFSATTRBIT_OWNER:
19099ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
19109ec7b004SRick Macklem j = fxdr_unsigned(int, *tl);
1911ef4edb70SRick Macklem if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1912a9285ae5SZack Kirsch error = NFSERR_BADXDR;
1913a9285ae5SZack Kirsch goto nfsmout;
1914a9285ae5SZack Kirsch }
19159ec7b004SRick Macklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
19169ec7b004SRick Macklem if (j > NFSV4_SMALLSTR)
19179ec7b004SRick Macklem cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
19189ec7b004SRick Macklem else
19199ec7b004SRick Macklem cp = namestr;
19209ec7b004SRick Macklem error = nfsrv_mtostr(nd, cp, j);
19219ec7b004SRick Macklem if (error) {
19229ec7b004SRick Macklem if (j > NFSV4_SMALLSTR)
19239ec7b004SRick Macklem free(cp, M_NFSSTRING);
1924a9285ae5SZack Kirsch goto nfsmout;
19259ec7b004SRick Macklem }
19269ec7b004SRick Macklem if (compare) {
19279ec7b004SRick Macklem if (!(*retcmpp)) {
19280658ac39SEdward Tomasz Napierala if (nfsv4_strtouid(nd, cp, j, &uid) ||
19299ec7b004SRick Macklem nap->na_uid != uid)
19309ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
19319ec7b004SRick Macklem }
19329ec7b004SRick Macklem } else if (nap != NULL) {
19330658ac39SEdward Tomasz Napierala if (nfsv4_strtouid(nd, cp, j, &uid))
1934f0db2b60SRick Macklem nap->na_uid =
1935f0db2b60SRick Macklem NFSD_VNET(nfsrv_defaultuid);
19369ec7b004SRick Macklem else
19379ec7b004SRick Macklem nap->na_uid = uid;
19389ec7b004SRick Macklem }
19399ec7b004SRick Macklem if (j > NFSV4_SMALLSTR)
19409ec7b004SRick Macklem free(cp, M_NFSSTRING);
19419ec7b004SRick Macklem break;
19429ec7b004SRick Macklem case NFSATTRBIT_OWNERGROUP:
19439ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
19449ec7b004SRick Macklem j = fxdr_unsigned(int, *tl);
1945ef4edb70SRick Macklem if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1946a9285ae5SZack Kirsch error = NFSERR_BADXDR;
1947a9285ae5SZack Kirsch goto nfsmout;
1948a9285ae5SZack Kirsch }
19499ec7b004SRick Macklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
19509ec7b004SRick Macklem if (j > NFSV4_SMALLSTR)
19519ec7b004SRick Macklem cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
19529ec7b004SRick Macklem else
19539ec7b004SRick Macklem cp = namestr;
19549ec7b004SRick Macklem error = nfsrv_mtostr(nd, cp, j);
19559ec7b004SRick Macklem if (error) {
19569ec7b004SRick Macklem if (j > NFSV4_SMALLSTR)
19579ec7b004SRick Macklem free(cp, M_NFSSTRING);
1958a9285ae5SZack Kirsch goto nfsmout;
19599ec7b004SRick Macklem }
19609ec7b004SRick Macklem if (compare) {
19619ec7b004SRick Macklem if (!(*retcmpp)) {
19622df8bd90SEdward Tomasz Napierala if (nfsv4_strtogid(nd, cp, j, &gid) ||
19639ec7b004SRick Macklem nap->na_gid != gid)
19649ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
19659ec7b004SRick Macklem }
19669ec7b004SRick Macklem } else if (nap != NULL) {
19672df8bd90SEdward Tomasz Napierala if (nfsv4_strtogid(nd, cp, j, &gid))
1968f0db2b60SRick Macklem nap->na_gid =
1969f0db2b60SRick Macklem NFSD_VNET(nfsrv_defaultgid);
19709ec7b004SRick Macklem else
19719ec7b004SRick Macklem nap->na_gid = gid;
19729ec7b004SRick Macklem }
19739ec7b004SRick Macklem if (j > NFSV4_SMALLSTR)
19749ec7b004SRick Macklem free(cp, M_NFSSTRING);
19759ec7b004SRick Macklem break;
19769ec7b004SRick Macklem case NFSATTRBIT_QUOTAHARD:
19779ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
19789ec7b004SRick Macklem if (sbp != NULL) {
1979cc426dd3SMateusz Guzik if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
19809ec7b004SRick Macklem freenum = sbp->f_bfree;
19819ec7b004SRick Macklem else
19829ec7b004SRick Macklem freenum = sbp->f_bavail;
19839ec7b004SRick Macklem #ifdef QUOTA
19849ec7b004SRick Macklem /*
19859ec7b004SRick Macklem * ufs_quotactl() insists that the uid argument
19869ec7b004SRick Macklem * equal p_ruid for non-root quota access, so
19879ec7b004SRick Macklem * we'll just make sure that's the case.
19889ec7b004SRick Macklem */
19899ec7b004SRick Macklem savuid = p->p_cred->p_ruid;
19909ec7b004SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
1991eea79fdeSAlan Somers if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
199252e63ec2SBrooks Davis USRQUOTA), cred->cr_uid, &dqb))
19939ec7b004SRick Macklem freenum = min(dqb.dqb_bhardlimit, freenum);
19949ec7b004SRick Macklem p->p_cred->p_ruid = savuid;
19959ec7b004SRick Macklem #endif /* QUOTA */
19969ec7b004SRick Macklem uquad = (u_int64_t)freenum;
19979ec7b004SRick Macklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
19989ec7b004SRick Macklem }
19999ec7b004SRick Macklem if (compare && !(*retcmpp)) {
20009ec7b004SRick Macklem if (uquad != fxdr_hyper(tl))
20019ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
20029ec7b004SRick Macklem }
20039ec7b004SRick Macklem attrsum += NFSX_HYPER;
20049ec7b004SRick Macklem break;
20059ec7b004SRick Macklem case NFSATTRBIT_QUOTASOFT:
20069ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
20079ec7b004SRick Macklem if (sbp != NULL) {
2008cc426dd3SMateusz Guzik if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
20099ec7b004SRick Macklem freenum = sbp->f_bfree;
20109ec7b004SRick Macklem else
20119ec7b004SRick Macklem freenum = sbp->f_bavail;
20129ec7b004SRick Macklem #ifdef QUOTA
20139ec7b004SRick Macklem /*
20149ec7b004SRick Macklem * ufs_quotactl() insists that the uid argument
20159ec7b004SRick Macklem * equal p_ruid for non-root quota access, so
20169ec7b004SRick Macklem * we'll just make sure that's the case.
20179ec7b004SRick Macklem */
20189ec7b004SRick Macklem savuid = p->p_cred->p_ruid;
20199ec7b004SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
2020eea79fdeSAlan Somers if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
202152e63ec2SBrooks Davis USRQUOTA), cred->cr_uid, &dqb))
20229ec7b004SRick Macklem freenum = min(dqb.dqb_bsoftlimit, freenum);
20239ec7b004SRick Macklem p->p_cred->p_ruid = savuid;
20249ec7b004SRick Macklem #endif /* QUOTA */
20259ec7b004SRick Macklem uquad = (u_int64_t)freenum;
20269ec7b004SRick Macklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
20279ec7b004SRick Macklem }
20289ec7b004SRick Macklem if (compare && !(*retcmpp)) {
20299ec7b004SRick Macklem if (uquad != fxdr_hyper(tl))
20309ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
20319ec7b004SRick Macklem }
20329ec7b004SRick Macklem attrsum += NFSX_HYPER;
20339ec7b004SRick Macklem break;
20349ec7b004SRick Macklem case NFSATTRBIT_QUOTAUSED:
20359ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
20369ec7b004SRick Macklem if (sbp != NULL) {
20379ec7b004SRick Macklem freenum = 0;
20389ec7b004SRick Macklem #ifdef QUOTA
20399ec7b004SRick Macklem /*
20409ec7b004SRick Macklem * ufs_quotactl() insists that the uid argument
20419ec7b004SRick Macklem * equal p_ruid for non-root quota access, so
20429ec7b004SRick Macklem * we'll just make sure that's the case.
20439ec7b004SRick Macklem */
20449ec7b004SRick Macklem savuid = p->p_cred->p_ruid;
20459ec7b004SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
2046eea79fdeSAlan Somers if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
204752e63ec2SBrooks Davis USRQUOTA), cred->cr_uid, &dqb))
20489ec7b004SRick Macklem freenum = dqb.dqb_curblocks;
20499ec7b004SRick Macklem p->p_cred->p_ruid = savuid;
20509ec7b004SRick Macklem #endif /* QUOTA */
20519ec7b004SRick Macklem uquad = (u_int64_t)freenum;
20529ec7b004SRick Macklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
20539ec7b004SRick Macklem }
20549ec7b004SRick Macklem if (compare && !(*retcmpp)) {
20559ec7b004SRick Macklem if (uquad != fxdr_hyper(tl))
20569ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
20579ec7b004SRick Macklem }
20589ec7b004SRick Macklem attrsum += NFSX_HYPER;
20599ec7b004SRick Macklem break;
20609ec7b004SRick Macklem case NFSATTRBIT_RAWDEV:
20619ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
20629ec7b004SRick Macklem j = fxdr_unsigned(int, *tl++);
20639ec7b004SRick Macklem k = fxdr_unsigned(int, *tl);
20649ec7b004SRick Macklem if (compare) {
20659ec7b004SRick Macklem if (!(*retcmpp)) {
20669ec7b004SRick Macklem if (nap->na_rdev != NFSMAKEDEV(j, k))
20679ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
20689ec7b004SRick Macklem }
20699ec7b004SRick Macklem } else if (nap != NULL) {
20709ec7b004SRick Macklem nap->na_rdev = NFSMAKEDEV(j, k);
20719ec7b004SRick Macklem }
20729ec7b004SRick Macklem attrsum += NFSX_V4SPECDATA;
20739ec7b004SRick Macklem break;
20749ec7b004SRick Macklem case NFSATTRBIT_SPACEAVAIL:
20759ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
20769ec7b004SRick Macklem if (compare) {
20772d90ef47SRick Macklem if (priv_check_cred(cred,
20782d90ef47SRick Macklem PRIV_VFS_BLOCKRESERVE))
20792d90ef47SRick Macklem uquad = sbp->f_bfree;
20802d90ef47SRick Macklem else
20812d90ef47SRick Macklem uquad = (uint64_t)sbp->f_bavail;
20822d90ef47SRick Macklem uquad *= sbp->f_bsize;
20832d90ef47SRick Macklem if (!(*retcmpp) && uquad != fxdr_hyper(tl))
20849ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
20859ec7b004SRick Macklem } else if (sfp != NULL) {
20869ec7b004SRick Macklem sfp->sf_abytes = fxdr_hyper(tl);
20879ec7b004SRick Macklem }
20889ec7b004SRick Macklem attrsum += NFSX_HYPER;
20899ec7b004SRick Macklem break;
20909ec7b004SRick Macklem case NFSATTRBIT_SPACEFREE:
20919ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
20929ec7b004SRick Macklem if (compare) {
20932d90ef47SRick Macklem uquad = sbp->f_bfree;
20942d90ef47SRick Macklem uquad *= sbp->f_bsize;
20952d90ef47SRick Macklem if (!(*retcmpp) && uquad != fxdr_hyper(tl))
20969ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
20979ec7b004SRick Macklem } else if (sfp != NULL) {
20989ec7b004SRick Macklem sfp->sf_fbytes = fxdr_hyper(tl);
20999ec7b004SRick Macklem }
21009ec7b004SRick Macklem attrsum += NFSX_HYPER;
21019ec7b004SRick Macklem break;
21029ec7b004SRick Macklem case NFSATTRBIT_SPACETOTAL:
21039ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
21049ec7b004SRick Macklem if (compare) {
21052d90ef47SRick Macklem uquad = sbp->f_blocks;
21062d90ef47SRick Macklem uquad *= sbp->f_bsize;
21072d90ef47SRick Macklem if (!(*retcmpp) && uquad != fxdr_hyper(tl))
21089ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
21099ec7b004SRick Macklem } else if (sfp != NULL) {
21109ec7b004SRick Macklem sfp->sf_tbytes = fxdr_hyper(tl);
21119ec7b004SRick Macklem }
21129ec7b004SRick Macklem attrsum += NFSX_HYPER;
21139ec7b004SRick Macklem break;
21149ec7b004SRick Macklem case NFSATTRBIT_SPACEUSED:
21159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
21169ec7b004SRick Macklem thyp = fxdr_hyper(tl);
21179ec7b004SRick Macklem if (compare) {
21189ec7b004SRick Macklem if (!(*retcmpp)) {
21199ec7b004SRick Macklem if ((u_int64_t)nap->na_bytes != thyp)
21209ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
21219ec7b004SRick Macklem }
21229ec7b004SRick Macklem } else if (nap != NULL) {
21239ec7b004SRick Macklem nap->na_bytes = thyp;
21249ec7b004SRick Macklem }
21259ec7b004SRick Macklem attrsum += NFSX_HYPER;
21269ec7b004SRick Macklem break;
21279ec7b004SRick Macklem case NFSATTRBIT_SYSTEM:
21289ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
21299ec7b004SRick Macklem if (compare && !(*retcmpp))
21309ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
21319ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
21329ec7b004SRick Macklem break;
21339ec7b004SRick Macklem case NFSATTRBIT_TIMEACCESS:
21349ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
21359ec7b004SRick Macklem fxdr_nfsv4time(tl, &temptime);
21369ec7b004SRick Macklem if (compare) {
21379ec7b004SRick Macklem if (!(*retcmpp)) {
21389ec7b004SRick Macklem if (!NFS_CMPTIME(temptime, nap->na_atime))
21399ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
21409ec7b004SRick Macklem }
21419ec7b004SRick Macklem } else if (nap != NULL) {
21429ec7b004SRick Macklem nap->na_atime = temptime;
21439ec7b004SRick Macklem }
21449ec7b004SRick Macklem attrsum += NFSX_V4TIME;
21459ec7b004SRick Macklem break;
21469ec7b004SRick Macklem case NFSATTRBIT_TIMEACCESSSET:
21479ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
21489ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
21499ec7b004SRick Macklem i = fxdr_unsigned(int, *tl);
21509ec7b004SRick Macklem if (i == NFSV4SATTRTIME_TOCLIENT) {
21519ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
21529ec7b004SRick Macklem attrsum += NFSX_V4TIME;
21539ec7b004SRick Macklem }
21549ec7b004SRick Macklem if (compare && !(*retcmpp))
21559ec7b004SRick Macklem *retcmpp = NFSERR_INVAL;
21569ec7b004SRick Macklem break;
21579ec7b004SRick Macklem case NFSATTRBIT_TIMEBACKUP:
21589ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
21599ec7b004SRick Macklem if (compare && !(*retcmpp))
21609ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
21619ec7b004SRick Macklem attrsum += NFSX_V4TIME;
21629ec7b004SRick Macklem break;
21639ec7b004SRick Macklem case NFSATTRBIT_TIMECREATE:
21649ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2165c07782e1SDoug Rabson fxdr_nfsv4time(tl, &temptime);
2166c07782e1SDoug Rabson if (compare) {
2167c07782e1SDoug Rabson if (!(*retcmpp)) {
2168c07782e1SDoug Rabson if (!NFS_CMPTIME(temptime, nap->na_btime))
2169c07782e1SDoug Rabson *retcmpp = NFSERR_NOTSAME;
2170c07782e1SDoug Rabson }
2171c07782e1SDoug Rabson } else if (nap != NULL) {
2172c07782e1SDoug Rabson nap->na_btime = temptime;
2173c07782e1SDoug Rabson }
21749ec7b004SRick Macklem attrsum += NFSX_V4TIME;
21759ec7b004SRick Macklem break;
21769ec7b004SRick Macklem case NFSATTRBIT_TIMEDELTA:
21779ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
21789ec7b004SRick Macklem if (fsp != NULL) {
21799ec7b004SRick Macklem if (compare) {
21809ec7b004SRick Macklem if (!(*retcmpp)) {
21819ec7b004SRick Macklem if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
21829ec7b004SRick Macklem fxdr_unsigned(u_int32_t, *(tl + 1)) ||
21839ec7b004SRick Macklem (u_int32_t)fsp->fs_timedelta.tv_nsec !=
21849ec7b004SRick Macklem (fxdr_unsigned(u_int32_t, *(tl + 2)) %
21859ec7b004SRick Macklem 1000000000) ||
21869ec7b004SRick Macklem *tl != 0)
21879ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
21889ec7b004SRick Macklem }
21899ec7b004SRick Macklem } else {
21909ec7b004SRick Macklem fxdr_nfsv4time(tl, &fsp->fs_timedelta);
21919ec7b004SRick Macklem }
21929ec7b004SRick Macklem }
21939ec7b004SRick Macklem attrsum += NFSX_V4TIME;
21949ec7b004SRick Macklem break;
21959ec7b004SRick Macklem case NFSATTRBIT_TIMEMETADATA:
21969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
21979ec7b004SRick Macklem fxdr_nfsv4time(tl, &temptime);
21989ec7b004SRick Macklem if (compare) {
21999ec7b004SRick Macklem if (!(*retcmpp)) {
22009ec7b004SRick Macklem if (!NFS_CMPTIME(temptime, nap->na_ctime))
22019ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
22029ec7b004SRick Macklem }
22039ec7b004SRick Macklem } else if (nap != NULL) {
22049ec7b004SRick Macklem nap->na_ctime = temptime;
22059ec7b004SRick Macklem }
22069ec7b004SRick Macklem attrsum += NFSX_V4TIME;
22079ec7b004SRick Macklem break;
22089ec7b004SRick Macklem case NFSATTRBIT_TIMEMODIFY:
22099ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
22109ec7b004SRick Macklem fxdr_nfsv4time(tl, &temptime);
22119ec7b004SRick Macklem if (compare) {
22129ec7b004SRick Macklem if (!(*retcmpp)) {
22139ec7b004SRick Macklem if (!NFS_CMPTIME(temptime, nap->na_mtime))
22149ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
22159ec7b004SRick Macklem }
22169ec7b004SRick Macklem } else if (nap != NULL) {
22179ec7b004SRick Macklem nap->na_mtime = temptime;
22189ec7b004SRick Macklem }
22199ec7b004SRick Macklem attrsum += NFSX_V4TIME;
22209ec7b004SRick Macklem break;
22219ec7b004SRick Macklem case NFSATTRBIT_TIMEMODIFYSET:
22229ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
22239ec7b004SRick Macklem attrsum += NFSX_UNSIGNED;
22249ec7b004SRick Macklem i = fxdr_unsigned(int, *tl);
22259ec7b004SRick Macklem if (i == NFSV4SATTRTIME_TOCLIENT) {
22269ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
22279ec7b004SRick Macklem attrsum += NFSX_V4TIME;
22289ec7b004SRick Macklem }
22299ec7b004SRick Macklem if (compare && !(*retcmpp))
22309ec7b004SRick Macklem *retcmpp = NFSERR_INVAL;
22319ec7b004SRick Macklem break;
22329ec7b004SRick Macklem case NFSATTRBIT_MOUNTEDONFILEID:
22339ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
22349ec7b004SRick Macklem thyp = fxdr_hyper(tl);
22359ec7b004SRick Macklem if (compare) {
22369ec7b004SRick Macklem if (!(*retcmpp)) {
223795ac7f1aSRick Macklem if (!vp || !nfsrv_atroot(vp, &thyp2))
223895ac7f1aSRick Macklem thyp2 = nap->na_fileid;
223995ac7f1aSRick Macklem if (thyp2 != thyp)
22409ec7b004SRick Macklem *retcmpp = NFSERR_NOTSAME;
22419ec7b004SRick Macklem }
224295ac7f1aSRick Macklem } else if (nap != NULL)
22439ec7b004SRick Macklem nap->na_mntonfileno = thyp;
22449ec7b004SRick Macklem attrsum += NFSX_HYPER;
22459ec7b004SRick Macklem break;
2246c59e4cc3SRick Macklem case NFSATTRBIT_SUPPATTREXCLCREAT:
2247c59e4cc3SRick Macklem retnotsup = 0;
2248c59e4cc3SRick Macklem error = nfsrv_getattrbits(nd, &retattrbits,
2249c59e4cc3SRick Macklem &cnt, &retnotsup);
2250c59e4cc3SRick Macklem if (error)
2251c59e4cc3SRick Macklem goto nfsmout;
2252c59e4cc3SRick Macklem if (compare && !(*retcmpp)) {
2253ea5776ecSRick Macklem NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2254ea5776ecSRick Macklem NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2255c59e4cc3SRick Macklem NFSCLRBIT_ATTRBIT(&checkattrbits,
2256c59e4cc3SRick Macklem NFSATTRBIT_TIMEACCESSSET);
2257c59e4cc3SRick Macklem if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2258c59e4cc3SRick Macklem || retnotsup)
2259c59e4cc3SRick Macklem *retcmpp = NFSERR_NOTSAME;
2260c59e4cc3SRick Macklem }
2261c59e4cc3SRick Macklem attrsum += cnt;
2262c59e4cc3SRick Macklem break;
226390d2dfabSRick Macklem case NFSATTRBIT_FSLAYOUTTYPE:
226490d2dfabSRick Macklem case NFSATTRBIT_LAYOUTTYPE:
226590d2dfabSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
226690d2dfabSRick Macklem attrsum += NFSX_UNSIGNED;
226790d2dfabSRick Macklem i = fxdr_unsigned(int, *tl);
2268480be96eSRick Macklem /*
2269480be96eSRick Macklem * The RFCs do not define an upper limit for the
2270480be96eSRick Macklem * number of layout types, but 32 should be more
2271480be96eSRick Macklem * than enough.
2272480be96eSRick Macklem */
2273480be96eSRick Macklem if (i < 0 || i > 32) {
2274480be96eSRick Macklem error = NFSERR_BADXDR;
2275480be96eSRick Macklem goto nfsmout;
2276480be96eSRick Macklem }
227790d2dfabSRick Macklem if (i > 0) {
227890d2dfabSRick Macklem NFSM_DISSECT(tl, u_int32_t *, i *
227990d2dfabSRick Macklem NFSX_UNSIGNED);
228090d2dfabSRick Macklem attrsum += i * NFSX_UNSIGNED;
228190d2dfabSRick Macklem j = fxdr_unsigned(int, *tl);
228290d2dfabSRick Macklem if (i == 1 && compare && !(*retcmpp) &&
228390d2dfabSRick Macklem (((nfsrv_doflexfile != 0 ||
228490d2dfabSRick Macklem nfsrv_maxpnfsmirror > 1) &&
228590d2dfabSRick Macklem j != NFSLAYOUT_FLEXFILE) ||
228690d2dfabSRick Macklem (nfsrv_doflexfile == 0 &&
228790d2dfabSRick Macklem j != NFSLAYOUT_NFSV4_1_FILES)))
228890d2dfabSRick Macklem *retcmpp = NFSERR_NOTSAME;
228990d2dfabSRick Macklem }
229090d2dfabSRick Macklem if (nfsrv_devidcnt == 0) {
229190d2dfabSRick Macklem if (compare && !(*retcmpp) && i > 0)
229290d2dfabSRick Macklem *retcmpp = NFSERR_NOTSAME;
229390d2dfabSRick Macklem } else {
229490d2dfabSRick Macklem if (compare && !(*retcmpp) && i != 1)
229590d2dfabSRick Macklem *retcmpp = NFSERR_NOTSAME;
229690d2dfabSRick Macklem }
229790d2dfabSRick Macklem break;
229890d2dfabSRick Macklem case NFSATTRBIT_LAYOUTALIGNMENT:
229990d2dfabSRick Macklem case NFSATTRBIT_LAYOUTBLKSIZE:
230090d2dfabSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
230190d2dfabSRick Macklem attrsum += NFSX_UNSIGNED;
230290d2dfabSRick Macklem i = fxdr_unsigned(int, *tl);
2303ee29e6f3SRick Macklem if (compare && !(*retcmpp) && i != nfs_srvmaxio)
230490d2dfabSRick Macklem *retcmpp = NFSERR_NOTSAME;
230590d2dfabSRick Macklem break;
2306709c1891SRick Macklem case NFSATTRBIT_CHANGEATTRTYPE:
2307709c1891SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2308709c1891SRick Macklem if (compare) {
2309709c1891SRick Macklem if (!(*retcmpp)) {
2310709c1891SRick Macklem tuint = NFSV4CHANGETYPE_UNDEFINED;
2311709c1891SRick Macklem if ((vp->v_mount->mnt_vfc->vfc_flags &
2312709c1891SRick Macklem VFCF_FILEREVINC) != 0)
2313709c1891SRick Macklem tuint = NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS;
2314709c1891SRick Macklem else if ((vp->v_mount->mnt_vfc->vfc_flags &
2315709c1891SRick Macklem VFCF_FILEREVCT) != 0)
2316709c1891SRick Macklem tuint = NFSV4CHANGETYPE_TIME_METADATA;
2317709c1891SRick Macklem if (fxdr_unsigned(uint32_t, *tl) != tuint)
2318709c1891SRick Macklem *retcmpp = NFSERR_NOTSAME;
2319709c1891SRick Macklem }
2320709c1891SRick Macklem }
2321709c1891SRick Macklem attrsum += NFSX_UNSIGNED;
2322709c1891SRick Macklem break;
23239ec7b004SRick Macklem default:
23249ec7b004SRick Macklem printf("EEK! nfsv4_loadattr unknown attr=%d\n",
23259ec7b004SRick Macklem bitpos);
23269ec7b004SRick Macklem if (compare && !(*retcmpp))
23279ec7b004SRick Macklem *retcmpp = NFSERR_ATTRNOTSUPP;
23289ec7b004SRick Macklem /*
23299ec7b004SRick Macklem * and get out of the loop, since we can't parse
2330bf312482SGordon Bergling * the unknown attribute data.
23319ec7b004SRick Macklem */
23329ec7b004SRick Macklem bitpos = NFSATTRBIT_MAX;
23339ec7b004SRick Macklem break;
233474b8d63dSPedro F. Giffuni }
23359ec7b004SRick Macklem }
23369ec7b004SRick Macklem
23379ec7b004SRick Macklem /*
23389ec7b004SRick Macklem * some clients pad the attrlist, so we need to skip over the
23399ec7b004SRick Macklem * padding.
23409ec7b004SRick Macklem */
23419ec7b004SRick Macklem if (attrsum > attrsize) {
23429ec7b004SRick Macklem error = NFSERR_BADXDR;
23439ec7b004SRick Macklem } else {
23449ec7b004SRick Macklem attrsize = NFSM_RNDUP(attrsize);
23459ec7b004SRick Macklem if (attrsum < attrsize)
23469ec7b004SRick Macklem error = nfsm_advance(nd, attrsize - attrsum, -1);
23479ec7b004SRick Macklem }
23489ec7b004SRick Macklem nfsmout:
2349f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
2350a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
23519ec7b004SRick Macklem return (error);
23529ec7b004SRick Macklem }
23539ec7b004SRick Macklem
23549ec7b004SRick Macklem /*
23559ec7b004SRick Macklem * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
23569ec7b004SRick Macklem * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
23579ec7b004SRick Macklem * The first argument is a pointer to an nfsv4lock structure.
23589ec7b004SRick Macklem * The second argument is 1 iff a blocking lock is wanted.
23599ec7b004SRick Macklem * If this argument is 0, the call waits until no thread either wants nor
23609ec7b004SRick Macklem * holds an exclusive lock.
23619ec7b004SRick Macklem * It returns 1 if the lock was acquired, 0 otherwise.
23629ec7b004SRick Macklem * If several processes call this function concurrently wanting the exclusive
23639ec7b004SRick Macklem * lock, one will get the lock and the rest will return without getting the
23649ec7b004SRick Macklem * lock. (If the caller must have the lock, it simply calls this function in a
23659ec7b004SRick Macklem * loop until the function returns 1 to indicate the lock was acquired.)
23669ec7b004SRick Macklem * Any usecnt must be decremented by calling nfsv4_relref() before
23679ec7b004SRick Macklem * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
23689ec7b004SRick Macklem * be called in a loop.
2369ff29f3b2SRick Macklem * The isleptp argument is set to indicate if the call slept, iff not NULL
2370ff29f3b2SRick Macklem * and the mp argument indicates to check for a forced dismount, iff not
2371ff29f3b2SRick Macklem * NULL.
23729ec7b004SRick Macklem */
2373b9cc3262SRyan Moeller int
nfsv4_lock(struct nfsv4lock * lp,int iwantlock,int * isleptp,struct mtx * mutex,struct mount * mp)23749ec7b004SRick Macklem nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
23755f742d38SRick Macklem struct mtx *mutex, struct mount *mp)
23769ec7b004SRick Macklem {
23779ec7b004SRick Macklem
23789ec7b004SRick Macklem if (isleptp)
23799ec7b004SRick Macklem *isleptp = 0;
23809ec7b004SRick Macklem /*
23819ec7b004SRick Macklem * If a lock is wanted, loop around until the lock is acquired by
23829ec7b004SRick Macklem * someone and then released. If I want the lock, try to acquire it.
23839ec7b004SRick Macklem * For a lock to be issued, no lock must be in force and the usecnt
23849ec7b004SRick Macklem * must be zero.
23859ec7b004SRick Macklem */
23869ec7b004SRick Macklem if (iwantlock) {
23879ec7b004SRick Macklem if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
23889ec7b004SRick Macklem lp->nfslock_usecnt == 0) {
23899ec7b004SRick Macklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
23909ec7b004SRick Macklem lp->nfslock_lock |= NFSV4LOCK_LOCK;
23919ec7b004SRick Macklem return (1);
23929ec7b004SRick Macklem }
23939ec7b004SRick Macklem lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
23949ec7b004SRick Macklem }
23959ec7b004SRick Macklem while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
239616f300faSRick Macklem if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2397ff29f3b2SRick Macklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2398ff29f3b2SRick Macklem return (0);
2399ff29f3b2SRick Macklem }
24009ec7b004SRick Macklem lp->nfslock_lock |= NFSV4LOCK_WANTED;
24019ec7b004SRick Macklem if (isleptp)
24029ec7b004SRick Macklem *isleptp = 1;
24035f742d38SRick Macklem msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
24049ec7b004SRick Macklem if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
24059ec7b004SRick Macklem lp->nfslock_usecnt == 0) {
24069ec7b004SRick Macklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
24079ec7b004SRick Macklem lp->nfslock_lock |= NFSV4LOCK_LOCK;
24089ec7b004SRick Macklem return (1);
24099ec7b004SRick Macklem }
24109ec7b004SRick Macklem }
24119ec7b004SRick Macklem return (0);
24129ec7b004SRick Macklem }
24139ec7b004SRick Macklem
24149ec7b004SRick Macklem /*
24159ec7b004SRick Macklem * Release the lock acquired by nfsv4_lock().
24169ec7b004SRick Macklem * The second argument is set to 1 to indicate the nfslock_usecnt should be
24179ec7b004SRick Macklem * incremented, as well.
24189ec7b004SRick Macklem */
2419b9cc3262SRyan Moeller void
nfsv4_unlock(struct nfsv4lock * lp,int incref)24209ec7b004SRick Macklem nfsv4_unlock(struct nfsv4lock *lp, int incref)
24219ec7b004SRick Macklem {
24229ec7b004SRick Macklem
24239ec7b004SRick Macklem lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
24249ec7b004SRick Macklem if (incref)
24259ec7b004SRick Macklem lp->nfslock_usecnt++;
24269ec7b004SRick Macklem nfsv4_wanted(lp);
24279ec7b004SRick Macklem }
24289ec7b004SRick Macklem
24299ec7b004SRick Macklem /*
24309ec7b004SRick Macklem * Release a reference cnt.
24319ec7b004SRick Macklem */
2432b9cc3262SRyan Moeller void
nfsv4_relref(struct nfsv4lock * lp)24339ec7b004SRick Macklem nfsv4_relref(struct nfsv4lock *lp)
24349ec7b004SRick Macklem {
24359ec7b004SRick Macklem
24369ec7b004SRick Macklem if (lp->nfslock_usecnt <= 0)
24379ec7b004SRick Macklem panic("nfsv4root ref cnt");
24389ec7b004SRick Macklem lp->nfslock_usecnt--;
24399ec7b004SRick Macklem if (lp->nfslock_usecnt == 0)
24409ec7b004SRick Macklem nfsv4_wanted(lp);
24419ec7b004SRick Macklem }
24429ec7b004SRick Macklem
24439ec7b004SRick Macklem /*
24449ec7b004SRick Macklem * Get a reference cnt.
24459ec7b004SRick Macklem * This function will wait for any exclusive lock to be released, but will
24469ec7b004SRick Macklem * not wait for threads that want the exclusive lock. If priority needs
24479ec7b004SRick Macklem * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
24489ec7b004SRick Macklem * with the 2nd argument == 0 should be done before calling nfsv4_getref().
244916f300faSRick Macklem * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2450ff29f3b2SRick Macklem * return without getting a refcnt for that case.
24519ec7b004SRick Macklem */
2452b9cc3262SRyan Moeller void
nfsv4_getref(struct nfsv4lock * lp,int * isleptp,struct mtx * mutex,struct mount * mp)24535f742d38SRick Macklem nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2454ff29f3b2SRick Macklem struct mount *mp)
24559ec7b004SRick Macklem {
24569ec7b004SRick Macklem
24579ec7b004SRick Macklem if (isleptp)
24589ec7b004SRick Macklem *isleptp = 0;
24599ec7b004SRick Macklem
24609ec7b004SRick Macklem /*
24619ec7b004SRick Macklem * Wait for a lock held.
24629ec7b004SRick Macklem */
24639ec7b004SRick Macklem while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
246416f300faSRick Macklem if (mp != NULL && NFSCL_FORCEDISM(mp))
2465ff29f3b2SRick Macklem return;
24669ec7b004SRick Macklem lp->nfslock_lock |= NFSV4LOCK_WANTED;
24679ec7b004SRick Macklem if (isleptp)
24689ec7b004SRick Macklem *isleptp = 1;
24695f742d38SRick Macklem msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
24709ec7b004SRick Macklem }
247116f300faSRick Macklem if (mp != NULL && NFSCL_FORCEDISM(mp))
2472ff29f3b2SRick Macklem return;
24739ec7b004SRick Macklem
24749ec7b004SRick Macklem lp->nfslock_usecnt++;
24759ec7b004SRick Macklem }
24769ec7b004SRick Macklem
24779ec7b004SRick Macklem /*
24782ec3f925SRick Macklem * Get a reference as above, but return failure instead of sleeping if
24792ec3f925SRick Macklem * an exclusive lock is held.
24802ec3f925SRick Macklem */
2481b9cc3262SRyan Moeller int
nfsv4_getref_nonblock(struct nfsv4lock * lp)24822ec3f925SRick Macklem nfsv4_getref_nonblock(struct nfsv4lock *lp)
24832ec3f925SRick Macklem {
24842ec3f925SRick Macklem
24852ec3f925SRick Macklem if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
24862ec3f925SRick Macklem return (0);
24872ec3f925SRick Macklem
24882ec3f925SRick Macklem lp->nfslock_usecnt++;
24892ec3f925SRick Macklem return (1);
24902ec3f925SRick Macklem }
24912ec3f925SRick Macklem
24922ec3f925SRick Macklem /*
2493a43fcbe3SRick Macklem * Test for a lock. Return 1 if locked, 0 otherwise.
2494a43fcbe3SRick Macklem */
2495b9cc3262SRyan Moeller int
nfsv4_testlock(struct nfsv4lock * lp)2496a43fcbe3SRick Macklem nfsv4_testlock(struct nfsv4lock *lp)
2497a43fcbe3SRick Macklem {
2498a43fcbe3SRick Macklem
2499a43fcbe3SRick Macklem if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2500a43fcbe3SRick Macklem lp->nfslock_usecnt == 0)
2501a43fcbe3SRick Macklem return (0);
2502a43fcbe3SRick Macklem return (1);
2503a43fcbe3SRick Macklem }
2504a43fcbe3SRick Macklem
2505a43fcbe3SRick Macklem /*
25069ec7b004SRick Macklem * Wake up anyone sleeping, waiting for this lock.
25079ec7b004SRick Macklem */
25089ec7b004SRick Macklem static void
nfsv4_wanted(struct nfsv4lock * lp)25099ec7b004SRick Macklem nfsv4_wanted(struct nfsv4lock *lp)
25109ec7b004SRick Macklem {
25119ec7b004SRick Macklem
25129ec7b004SRick Macklem if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
25139ec7b004SRick Macklem lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
25149ec7b004SRick Macklem wakeup((caddr_t)&lp->nfslock_lock);
25159ec7b004SRick Macklem }
25169ec7b004SRick Macklem }
25179ec7b004SRick Macklem
25189ec7b004SRick Macklem /*
25199ec7b004SRick Macklem * Copy a string from an mbuf list into a character array.
25209ec7b004SRick Macklem * Return EBADRPC if there is an mbuf error,
25219ec7b004SRick Macklem * 0 otherwise.
25229ec7b004SRick Macklem */
2523b9cc3262SRyan Moeller int
nfsrv_mtostr(struct nfsrv_descript * nd,char * str,int siz)25249ec7b004SRick Macklem nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
25259ec7b004SRick Macklem {
25269ec7b004SRick Macklem char *cp;
25279ec7b004SRick Macklem int xfer, len;
2528ae070589SRick Macklem struct mbuf *mp;
25299ec7b004SRick Macklem int rem, error = 0;
25309ec7b004SRick Macklem
25319ec7b004SRick Macklem mp = nd->nd_md;
25329ec7b004SRick Macklem cp = nd->nd_dpos;
2533c948a17aSRick Macklem len = mtod(mp, caddr_t) + mp->m_len - cp;
25349ec7b004SRick Macklem rem = NFSM_RNDUP(siz) - siz;
25359ec7b004SRick Macklem while (siz > 0) {
25369ec7b004SRick Macklem if (len > siz)
25379ec7b004SRick Macklem xfer = siz;
25389ec7b004SRick Macklem else
25399ec7b004SRick Macklem xfer = len;
25409ec7b004SRick Macklem NFSBCOPY(cp, str, xfer);
25419ec7b004SRick Macklem str += xfer;
25429ec7b004SRick Macklem siz -= xfer;
25439ec7b004SRick Macklem if (siz > 0) {
2544c948a17aSRick Macklem mp = mp->m_next;
2545a9285ae5SZack Kirsch if (mp == NULL) {
2546a9285ae5SZack Kirsch error = EBADRPC;
2547a9285ae5SZack Kirsch goto out;
2548a9285ae5SZack Kirsch }
2549c948a17aSRick Macklem cp = mtod(mp, caddr_t);
2550c948a17aSRick Macklem len = mp->m_len;
25519ec7b004SRick Macklem } else {
25529ec7b004SRick Macklem cp += xfer;
25539ec7b004SRick Macklem len -= xfer;
25549ec7b004SRick Macklem }
25559ec7b004SRick Macklem }
25569ec7b004SRick Macklem *str = '\0';
25579ec7b004SRick Macklem nd->nd_dpos = cp;
25589ec7b004SRick Macklem nd->nd_md = mp;
25599ec7b004SRick Macklem if (rem > 0) {
25609ec7b004SRick Macklem if (len < rem)
25619ec7b004SRick Macklem error = nfsm_advance(nd, rem, len);
25629ec7b004SRick Macklem else
25639ec7b004SRick Macklem nd->nd_dpos += rem;
25649ec7b004SRick Macklem }
2565a9285ae5SZack Kirsch
2566a9285ae5SZack Kirsch out:
2567a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
25689ec7b004SRick Macklem return (error);
25699ec7b004SRick Macklem }
25709ec7b004SRick Macklem
25719ec7b004SRick Macklem /*
25729ec7b004SRick Macklem * Fill in the attributes as marked by the bitmap (V4).
25739ec7b004SRick Macklem */
2574b9cc3262SRyan Moeller int
nfsv4_fillattr(struct nfsrv_descript * nd,struct mount * mp,vnode_t vp,NFSACL_T * saclp,struct vattr * vap,fhandle_t * fhp,int rderror,nfsattrbit_t * attrbitp,struct ucred * cred,NFSPROC_T * p,int isdgram,int reterr,int supports_nfsv4acls,int at_root,uint64_t mounted_on_fileno,struct statfs * pnfssf)257507c0c166SRick Macklem nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
257607c0c166SRick Macklem NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
257707c0c166SRick Macklem nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
257890d2dfabSRick Macklem int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
257990d2dfabSRick Macklem struct statfs *pnfssf)
25809ec7b004SRick Macklem {
25819ec7b004SRick Macklem int bitpos, retnum = 0;
25829ec7b004SRick Macklem u_int32_t *tl;
25839ec7b004SRick Macklem int siz, prefixnum, error;
25849ec7b004SRick Macklem u_char *cp, namestr[NFSV4_SMALLSTR];
25859ec7b004SRick Macklem nfsattrbit_t attrbits, retbits;
25869ec7b004SRick Macklem nfsattrbit_t *retbitp = &retbits;
25879ec7b004SRick Macklem u_int32_t freenum, *retnump;
25889ec7b004SRick Macklem u_int64_t uquad;
25892f304845SKonstantin Belousov struct statfs *fs;
25909ec7b004SRick Macklem struct nfsfsinfo fsinf;
25919ec7b004SRick Macklem struct timespec temptime;
25929ec7b004SRick Macklem NFSACL_T *aclp, *naclp = NULL;
2593c057a378SRick Macklem size_t atsiz;
2594c057a378SRick Macklem bool xattrsupp;
25959ec7b004SRick Macklem #ifdef QUOTA
25969ec7b004SRick Macklem struct dqblk dqb;
25979ec7b004SRick Macklem uid_t savuid;
25989ec7b004SRick Macklem #endif
25999ec7b004SRick Macklem
26009ec7b004SRick Macklem /*
26019ec7b004SRick Macklem * First, set the bits that can be filled and get fsinfo.
26029ec7b004SRick Macklem */
26039ec7b004SRick Macklem NFSSET_ATTRBIT(retbitp, attrbitp);
2604b921158aSRick Macklem /*
2605b921158aSRick Macklem * If both p and cred are NULL, it is a client side setattr call.
2606b921158aSRick Macklem * If both p and cred are not NULL, it is a server side reply call.
2607b921158aSRick Macklem * If p is not NULL and cred is NULL, it is a client side callback
2608b921158aSRick Macklem * reply call.
2609b921158aSRick Macklem */
26109ec7b004SRick Macklem if (p == NULL && cred == NULL) {
2611ea5776ecSRick Macklem NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
26129ec7b004SRick Macklem aclp = saclp;
26139ec7b004SRick Macklem } else {
2614ea5776ecSRick Macklem NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2615c3e22f83SRick Macklem naclp = acl_alloc(M_WAITOK);
26169ec7b004SRick Macklem aclp = naclp;
26179ec7b004SRick Macklem }
26189ec7b004SRick Macklem nfsvno_getfs(&fsinf, isdgram);
26199ec7b004SRick Macklem /*
26209ec7b004SRick Macklem * Get the VFS_STATFS(), since some attributes need them.
26219ec7b004SRick Macklem */
26222f304845SKonstantin Belousov fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
26239ec7b004SRick Macklem if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
26242f304845SKonstantin Belousov error = VFS_STATFS(mp, fs);
26259ec7b004SRick Macklem if (error != 0) {
26269ec7b004SRick Macklem if (reterr) {
26279ec7b004SRick Macklem nd->nd_repstat = NFSERR_ACCES;
26282f304845SKonstantin Belousov free(fs, M_STATFS);
26299ec7b004SRick Macklem return (0);
26309ec7b004SRick Macklem }
26319ec7b004SRick Macklem NFSCLRSTATFS_ATTRBIT(retbitp);
26329ec7b004SRick Macklem }
2633d70ca5b0SRick Macklem /*
2634d70ca5b0SRick Macklem * Since NFS handles these values as unsigned on the
2635d70ca5b0SRick Macklem * wire, there is no way to represent negative values,
2636d70ca5b0SRick Macklem * so set them to 0. Without this, they will appear
2637d70ca5b0SRick Macklem * to be very large positive values for clients like
2638d70ca5b0SRick Macklem * Solaris10.
2639d70ca5b0SRick Macklem */
2640d70ca5b0SRick Macklem if (fs->f_bavail < 0)
2641d70ca5b0SRick Macklem fs->f_bavail = 0;
2642d70ca5b0SRick Macklem if (fs->f_ffree < 0)
2643d70ca5b0SRick Macklem fs->f_ffree = 0;
26449ec7b004SRick Macklem }
26459ec7b004SRick Macklem
26469ec7b004SRick Macklem /*
26479ec7b004SRick Macklem * And the NFSv4 ACL...
26489ec7b004SRick Macklem */
264974991298SEdward Tomasz Napierala if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
265074991298SEdward Tomasz Napierala (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2651a09001a8SRick Macklem supports_nfsv4acls == 0))) {
26529ec7b004SRick Macklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
26539ec7b004SRick Macklem }
26549ec7b004SRick Macklem if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
26559ec7b004SRick Macklem if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2656a09001a8SRick Macklem supports_nfsv4acls == 0)) {
26579ec7b004SRick Macklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
26589ec7b004SRick Macklem } else if (naclp != NULL) {
265998f234f3SZack Kirsch if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
26608207db3eSRick Macklem error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
26619ec7b004SRick Macklem if (error == 0)
266217891d00SRick Macklem error = VOP_GETACL(vp, ACL_TYPE_NFS4,
266317891d00SRick Macklem naclp, cred, p);
2664b249ce48SMateusz Guzik NFSVOPUNLOCK(vp);
266517891d00SRick Macklem } else
266617891d00SRick Macklem error = NFSERR_PERM;
26679ec7b004SRick Macklem if (error != 0) {
26689ec7b004SRick Macklem if (reterr) {
26699ec7b004SRick Macklem nd->nd_repstat = NFSERR_ACCES;
26702f304845SKonstantin Belousov free(fs, M_STATFS);
26719ec7b004SRick Macklem return (0);
26729ec7b004SRick Macklem }
26739ec7b004SRick Macklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
26749ec7b004SRick Macklem }
26759ec7b004SRick Macklem }
26769ec7b004SRick Macklem }
2677d8a5961fSMarcelo Araujo
2678c057a378SRick Macklem /* Check to see if Extended Attributes are supported. */
2679c057a378SRick Macklem xattrsupp = false;
2680c057a378SRick Macklem if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
2681c057a378SRick Macklem if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2682c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
2683c057a378SRick Macklem "xxx", NULL, &atsiz, cred, p);
2684b249ce48SMateusz Guzik NFSVOPUNLOCK(vp);
2685c057a378SRick Macklem if (error != EOPNOTSUPP)
2686c057a378SRick Macklem xattrsupp = true;
2687c057a378SRick Macklem }
2688c057a378SRick Macklem }
2689c057a378SRick Macklem
26909ec7b004SRick Macklem /*
26919ec7b004SRick Macklem * Put out the attribute bitmap for the ones being filled in
26929ec7b004SRick Macklem * and get the field for the number of attributes returned.
26939ec7b004SRick Macklem */
26949ec7b004SRick Macklem prefixnum = nfsrv_putattrbit(nd, retbitp);
26959ec7b004SRick Macklem NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
26969ec7b004SRick Macklem prefixnum += NFSX_UNSIGNED;
26979ec7b004SRick Macklem
26989ec7b004SRick Macklem /*
26999ec7b004SRick Macklem * Now, loop around filling in the attributes for each bit set.
27009ec7b004SRick Macklem */
27019ec7b004SRick Macklem for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
27029ec7b004SRick Macklem if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
27039ec7b004SRick Macklem switch (bitpos) {
27049ec7b004SRick Macklem case NFSATTRBIT_SUPPORTEDATTRS:
2705ea5776ecSRick Macklem NFSSETSUPP_ATTRBIT(&attrbits, nd);
27069ec7b004SRick Macklem if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2707a09001a8SRick Macklem && supports_nfsv4acls == 0)) {
27089ec7b004SRick Macklem NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
27099ec7b004SRick Macklem NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
27109ec7b004SRick Macklem }
27119ec7b004SRick Macklem retnum += nfsrv_putattrbit(nd, &attrbits);
27129ec7b004SRick Macklem break;
27139ec7b004SRick Macklem case NFSATTRBIT_TYPE:
27149ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27159ec7b004SRick Macklem *tl = vtonfsv34_type(vap->va_type);
27169ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27179ec7b004SRick Macklem break;
27189ec7b004SRick Macklem case NFSATTRBIT_FHEXPIRETYPE:
27199ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27209ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
27219ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27229ec7b004SRick Macklem break;
27239ec7b004SRick Macklem case NFSATTRBIT_CHANGE:
27249ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
27259ec7b004SRick Macklem txdr_hyper(vap->va_filerev, tl);
27269ec7b004SRick Macklem retnum += NFSX_HYPER;
27279ec7b004SRick Macklem break;
27289ec7b004SRick Macklem case NFSATTRBIT_SIZE:
27299ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
27309ec7b004SRick Macklem txdr_hyper(vap->va_size, tl);
27319ec7b004SRick Macklem retnum += NFSX_HYPER;
27329ec7b004SRick Macklem break;
27339ec7b004SRick Macklem case NFSATTRBIT_LINKSUPPORT:
27349ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27359ec7b004SRick Macklem if (fsinf.fs_properties & NFSV3FSINFO_LINK)
27369ec7b004SRick Macklem *tl = newnfs_true;
27379ec7b004SRick Macklem else
27389ec7b004SRick Macklem *tl = newnfs_false;
27399ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27409ec7b004SRick Macklem break;
27419ec7b004SRick Macklem case NFSATTRBIT_SYMLINKSUPPORT:
27429ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27439ec7b004SRick Macklem if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
27449ec7b004SRick Macklem *tl = newnfs_true;
27459ec7b004SRick Macklem else
27469ec7b004SRick Macklem *tl = newnfs_false;
27479ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27489ec7b004SRick Macklem break;
27499ec7b004SRick Macklem case NFSATTRBIT_NAMEDATTR:
27509ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27519ec7b004SRick Macklem *tl = newnfs_false;
27529ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27539ec7b004SRick Macklem break;
27549ec7b004SRick Macklem case NFSATTRBIT_FSID:
27559ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
27569ec7b004SRick Macklem *tl++ = 0;
275707c0c166SRick Macklem *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
27589ec7b004SRick Macklem *tl++ = 0;
275907c0c166SRick Macklem *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
27609ec7b004SRick Macklem retnum += NFSX_V4FSID;
27619ec7b004SRick Macklem break;
27629ec7b004SRick Macklem case NFSATTRBIT_UNIQUEHANDLES:
27639ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27649ec7b004SRick Macklem *tl = newnfs_true;
27659ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27669ec7b004SRick Macklem break;
27679ec7b004SRick Macklem case NFSATTRBIT_LEASETIME:
27689ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27699ec7b004SRick Macklem *tl = txdr_unsigned(nfsrv_lease);
27709ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27719ec7b004SRick Macklem break;
27729ec7b004SRick Macklem case NFSATTRBIT_RDATTRERROR:
27739ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27749ec7b004SRick Macklem *tl = txdr_unsigned(rderror);
27759ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27769ec7b004SRick Macklem break;
27779ec7b004SRick Macklem /*
27789ec7b004SRick Macklem * Recommended Attributes. (Only the supported ones.)
27799ec7b004SRick Macklem */
27809ec7b004SRick Macklem case NFSATTRBIT_ACL:
27811ebc14c9SRick Macklem retnum += nfsrv_buildacl(nd, aclp, vp->v_type, p);
27829ec7b004SRick Macklem break;
27839ec7b004SRick Macklem case NFSATTRBIT_ACLSUPPORT:
27849ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27859ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
27869ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27879ec7b004SRick Macklem break;
27889ec7b004SRick Macklem case NFSATTRBIT_CANSETTIME:
27899ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27909ec7b004SRick Macklem if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
27919ec7b004SRick Macklem *tl = newnfs_true;
27929ec7b004SRick Macklem else
27939ec7b004SRick Macklem *tl = newnfs_false;
27949ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
27959ec7b004SRick Macklem break;
27969ec7b004SRick Macklem case NFSATTRBIT_CASEINSENSITIVE:
27979ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27989ec7b004SRick Macklem *tl = newnfs_false;
27999ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28009ec7b004SRick Macklem break;
28019ec7b004SRick Macklem case NFSATTRBIT_CASEPRESERVING:
28029ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
28039ec7b004SRick Macklem *tl = newnfs_true;
28049ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28059ec7b004SRick Macklem break;
28069ec7b004SRick Macklem case NFSATTRBIT_CHOWNRESTRICTED:
28079ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2808061c683cSZack Kirsch *tl = newnfs_true;
28099ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28109ec7b004SRick Macklem break;
28119ec7b004SRick Macklem case NFSATTRBIT_FILEHANDLE:
2812896516e5SRick Macklem retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
28139ec7b004SRick Macklem break;
28149ec7b004SRick Macklem case NFSATTRBIT_FILEID:
28159ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
281695ac7f1aSRick Macklem uquad = vap->va_fileid;
281795ac7f1aSRick Macklem txdr_hyper(uquad, tl);
28189ec7b004SRick Macklem retnum += NFSX_HYPER;
28199ec7b004SRick Macklem break;
28209ec7b004SRick Macklem case NFSATTRBIT_FILESAVAIL:
28212d90ef47SRick Macklem freenum = nfsv4_filesavail(fs, mp);
28229ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
28239ec7b004SRick Macklem *tl++ = 0;
28249ec7b004SRick Macklem *tl = txdr_unsigned(freenum);
28259ec7b004SRick Macklem retnum += NFSX_HYPER;
28269ec7b004SRick Macklem break;
28279ec7b004SRick Macklem case NFSATTRBIT_FILESFREE:
28289ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
28299ec7b004SRick Macklem *tl++ = 0;
28302f304845SKonstantin Belousov *tl = txdr_unsigned(fs->f_ffree);
28319ec7b004SRick Macklem retnum += NFSX_HYPER;
28329ec7b004SRick Macklem break;
28339ec7b004SRick Macklem case NFSATTRBIT_FILESTOTAL:
28349ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
28359ec7b004SRick Macklem *tl++ = 0;
28362f304845SKonstantin Belousov *tl = txdr_unsigned(fs->f_files);
28379ec7b004SRick Macklem retnum += NFSX_HYPER;
28389ec7b004SRick Macklem break;
28399ec7b004SRick Macklem case NFSATTRBIT_FSLOCATIONS:
28409ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
28419ec7b004SRick Macklem *tl++ = 0;
28429ec7b004SRick Macklem *tl = 0;
28439ec7b004SRick Macklem retnum += 2 * NFSX_UNSIGNED;
28449ec7b004SRick Macklem break;
28459ec7b004SRick Macklem case NFSATTRBIT_HOMOGENEOUS:
28469ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
28479ec7b004SRick Macklem if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
28489ec7b004SRick Macklem *tl = newnfs_true;
28499ec7b004SRick Macklem else
28509ec7b004SRick Macklem *tl = newnfs_false;
28519ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28529ec7b004SRick Macklem break;
28539ec7b004SRick Macklem case NFSATTRBIT_MAXFILESIZE:
28549ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
28559ec7b004SRick Macklem uquad = NFSRV_MAXFILESIZE;
28569ec7b004SRick Macklem txdr_hyper(uquad, tl);
28579ec7b004SRick Macklem retnum += NFSX_HYPER;
28589ec7b004SRick Macklem break;
28599ec7b004SRick Macklem case NFSATTRBIT_MAXLINK:
28609ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
286155384243SJohn Baldwin *tl = txdr_unsigned(NFS_LINK_MAX);
28629ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28639ec7b004SRick Macklem break;
28649ec7b004SRick Macklem case NFSATTRBIT_MAXNAME:
28659ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
28669ec7b004SRick Macklem *tl = txdr_unsigned(NFS_MAXNAMLEN);
28679ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28689ec7b004SRick Macklem break;
28699ec7b004SRick Macklem case NFSATTRBIT_MAXREAD:
28709ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
28719ec7b004SRick Macklem *tl++ = 0;
28729ec7b004SRick Macklem *tl = txdr_unsigned(fsinf.fs_rtmax);
28739ec7b004SRick Macklem retnum += NFSX_HYPER;
28749ec7b004SRick Macklem break;
28759ec7b004SRick Macklem case NFSATTRBIT_MAXWRITE:
28769ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
28779ec7b004SRick Macklem *tl++ = 0;
28789ec7b004SRick Macklem *tl = txdr_unsigned(fsinf.fs_wtmax);
28799ec7b004SRick Macklem retnum += NFSX_HYPER;
28809ec7b004SRick Macklem break;
28819ec7b004SRick Macklem case NFSATTRBIT_MODE:
28829ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
28839ec7b004SRick Macklem *tl = vtonfsv34_mode(vap->va_mode);
28849ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28859ec7b004SRick Macklem break;
28869ec7b004SRick Macklem case NFSATTRBIT_NOTRUNC:
28879ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
28889ec7b004SRick Macklem *tl = newnfs_true;
28899ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28909ec7b004SRick Macklem break;
28919ec7b004SRick Macklem case NFSATTRBIT_NUMLINKS:
28929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
28939ec7b004SRick Macklem *tl = txdr_unsigned(vap->va_nlink);
28949ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
28959ec7b004SRick Macklem break;
28969ec7b004SRick Macklem case NFSATTRBIT_OWNER:
28979ec7b004SRick Macklem cp = namestr;
28980f86b94aSEdward Tomasz Napierala nfsv4_uidtostr(vap->va_uid, &cp, &siz);
28999ec7b004SRick Macklem retnum += nfsm_strtom(nd, cp, siz);
29009ec7b004SRick Macklem if (cp != namestr)
29019ec7b004SRick Macklem free(cp, M_NFSSTRING);
29029ec7b004SRick Macklem break;
29039ec7b004SRick Macklem case NFSATTRBIT_OWNERGROUP:
29049ec7b004SRick Macklem cp = namestr;
2905c703cba8SEdward Tomasz Napierala nfsv4_gidtostr(vap->va_gid, &cp, &siz);
29069ec7b004SRick Macklem retnum += nfsm_strtom(nd, cp, siz);
29079ec7b004SRick Macklem if (cp != namestr)
29089ec7b004SRick Macklem free(cp, M_NFSSTRING);
29099ec7b004SRick Macklem break;
29109ec7b004SRick Macklem case NFSATTRBIT_QUOTAHARD:
2911cc426dd3SMateusz Guzik if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
29122f304845SKonstantin Belousov freenum = fs->f_bfree;
29139ec7b004SRick Macklem else
29142f304845SKonstantin Belousov freenum = fs->f_bavail;
29159ec7b004SRick Macklem #ifdef QUOTA
29169ec7b004SRick Macklem /*
29179ec7b004SRick Macklem * ufs_quotactl() insists that the uid argument
29189ec7b004SRick Macklem * equal p_ruid for non-root quota access, so
29199ec7b004SRick Macklem * we'll just make sure that's the case.
29209ec7b004SRick Macklem */
29219ec7b004SRick Macklem savuid = p->p_cred->p_ruid;
29229ec7b004SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
292307c0c166SRick Macklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
292452e63ec2SBrooks Davis cred->cr_uid, &dqb))
29259ec7b004SRick Macklem freenum = min(dqb.dqb_bhardlimit, freenum);
29269ec7b004SRick Macklem p->p_cred->p_ruid = savuid;
29279ec7b004SRick Macklem #endif /* QUOTA */
29289ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
29299ec7b004SRick Macklem uquad = (u_int64_t)freenum;
29302f304845SKonstantin Belousov NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
29319ec7b004SRick Macklem txdr_hyper(uquad, tl);
29329ec7b004SRick Macklem retnum += NFSX_HYPER;
29339ec7b004SRick Macklem break;
29349ec7b004SRick Macklem case NFSATTRBIT_QUOTASOFT:
2935cc426dd3SMateusz Guzik if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
29362f304845SKonstantin Belousov freenum = fs->f_bfree;
29379ec7b004SRick Macklem else
29382f304845SKonstantin Belousov freenum = fs->f_bavail;
29399ec7b004SRick Macklem #ifdef QUOTA
29409ec7b004SRick Macklem /*
29419ec7b004SRick Macklem * ufs_quotactl() insists that the uid argument
29429ec7b004SRick Macklem * equal p_ruid for non-root quota access, so
29439ec7b004SRick Macklem * we'll just make sure that's the case.
29449ec7b004SRick Macklem */
29459ec7b004SRick Macklem savuid = p->p_cred->p_ruid;
29469ec7b004SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
294707c0c166SRick Macklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
294852e63ec2SBrooks Davis cred->cr_uid, &dqb))
29499ec7b004SRick Macklem freenum = min(dqb.dqb_bsoftlimit, freenum);
29509ec7b004SRick Macklem p->p_cred->p_ruid = savuid;
29519ec7b004SRick Macklem #endif /* QUOTA */
29529ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
29539ec7b004SRick Macklem uquad = (u_int64_t)freenum;
29542f304845SKonstantin Belousov NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
29559ec7b004SRick Macklem txdr_hyper(uquad, tl);
29569ec7b004SRick Macklem retnum += NFSX_HYPER;
29579ec7b004SRick Macklem break;
29589ec7b004SRick Macklem case NFSATTRBIT_QUOTAUSED:
29599ec7b004SRick Macklem freenum = 0;
29609ec7b004SRick Macklem #ifdef QUOTA
29619ec7b004SRick Macklem /*
29629ec7b004SRick Macklem * ufs_quotactl() insists that the uid argument
29639ec7b004SRick Macklem * equal p_ruid for non-root quota access, so
29649ec7b004SRick Macklem * we'll just make sure that's the case.
29659ec7b004SRick Macklem */
29669ec7b004SRick Macklem savuid = p->p_cred->p_ruid;
29679ec7b004SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
296807c0c166SRick Macklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
296952e63ec2SBrooks Davis cred->cr_uid, &dqb))
29709ec7b004SRick Macklem freenum = dqb.dqb_curblocks;
29719ec7b004SRick Macklem p->p_cred->p_ruid = savuid;
29729ec7b004SRick Macklem #endif /* QUOTA */
29739ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
29749ec7b004SRick Macklem uquad = (u_int64_t)freenum;
29752f304845SKonstantin Belousov NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
29769ec7b004SRick Macklem txdr_hyper(uquad, tl);
29779ec7b004SRick Macklem retnum += NFSX_HYPER;
29789ec7b004SRick Macklem break;
29799ec7b004SRick Macklem case NFSATTRBIT_RAWDEV:
29809ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
29819ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
29829ec7b004SRick Macklem *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
29839ec7b004SRick Macklem retnum += NFSX_V4SPECDATA;
29849ec7b004SRick Macklem break;
29859ec7b004SRick Macklem case NFSATTRBIT_SPACEAVAIL:
29869ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2987cc426dd3SMateusz Guzik if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
298890d2dfabSRick Macklem if (pnfssf != NULL)
298990d2dfabSRick Macklem uquad = (u_int64_t)pnfssf->f_bfree;
299090d2dfabSRick Macklem else
29912f304845SKonstantin Belousov uquad = (u_int64_t)fs->f_bfree;
299290d2dfabSRick Macklem } else {
299390d2dfabSRick Macklem if (pnfssf != NULL)
299490d2dfabSRick Macklem uquad = (u_int64_t)pnfssf->f_bavail;
29959ec7b004SRick Macklem else
29962f304845SKonstantin Belousov uquad = (u_int64_t)fs->f_bavail;
299790d2dfabSRick Macklem }
299890d2dfabSRick Macklem if (pnfssf != NULL)
299990d2dfabSRick Macklem uquad *= pnfssf->f_bsize;
300090d2dfabSRick Macklem else
30012f304845SKonstantin Belousov uquad *= fs->f_bsize;
30029ec7b004SRick Macklem txdr_hyper(uquad, tl);
30039ec7b004SRick Macklem retnum += NFSX_HYPER;
30049ec7b004SRick Macklem break;
30059ec7b004SRick Macklem case NFSATTRBIT_SPACEFREE:
30069ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
300790d2dfabSRick Macklem if (pnfssf != NULL) {
300890d2dfabSRick Macklem uquad = (u_int64_t)pnfssf->f_bfree;
300990d2dfabSRick Macklem uquad *= pnfssf->f_bsize;
301090d2dfabSRick Macklem } else {
30112f304845SKonstantin Belousov uquad = (u_int64_t)fs->f_bfree;
30122f304845SKonstantin Belousov uquad *= fs->f_bsize;
301390d2dfabSRick Macklem }
30149ec7b004SRick Macklem txdr_hyper(uquad, tl);
30159ec7b004SRick Macklem retnum += NFSX_HYPER;
30169ec7b004SRick Macklem break;
30179ec7b004SRick Macklem case NFSATTRBIT_SPACETOTAL:
30189ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
301990d2dfabSRick Macklem if (pnfssf != NULL) {
302090d2dfabSRick Macklem uquad = (u_int64_t)pnfssf->f_blocks;
302190d2dfabSRick Macklem uquad *= pnfssf->f_bsize;
302290d2dfabSRick Macklem } else {
30232f304845SKonstantin Belousov uquad = (u_int64_t)fs->f_blocks;
30242f304845SKonstantin Belousov uquad *= fs->f_bsize;
302590d2dfabSRick Macklem }
30269ec7b004SRick Macklem txdr_hyper(uquad, tl);
30279ec7b004SRick Macklem retnum += NFSX_HYPER;
30289ec7b004SRick Macklem break;
30299ec7b004SRick Macklem case NFSATTRBIT_SPACEUSED:
30309ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
30319ec7b004SRick Macklem txdr_hyper(vap->va_bytes, tl);
30329ec7b004SRick Macklem retnum += NFSX_HYPER;
30339ec7b004SRick Macklem break;
30349ec7b004SRick Macklem case NFSATTRBIT_TIMEACCESS:
30359ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
30369ec7b004SRick Macklem txdr_nfsv4time(&vap->va_atime, tl);
30379ec7b004SRick Macklem retnum += NFSX_V4TIME;
30389ec7b004SRick Macklem break;
30399ec7b004SRick Macklem case NFSATTRBIT_TIMEACCESSSET:
30405055536eSJohn Baldwin if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
30419ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
30429ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
30439ec7b004SRick Macklem txdr_nfsv4time(&vap->va_atime, tl);
30449ec7b004SRick Macklem retnum += NFSX_V4SETTIME;
30459ec7b004SRick Macklem } else {
30469ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
30479ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
30489ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
30499ec7b004SRick Macklem }
30509ec7b004SRick Macklem break;
30519ec7b004SRick Macklem case NFSATTRBIT_TIMEDELTA:
30529ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
30539ec7b004SRick Macklem temptime.tv_sec = 0;
30549ec7b004SRick Macklem temptime.tv_nsec = 1000000000 / hz;
30559ec7b004SRick Macklem txdr_nfsv4time(&temptime, tl);
30569ec7b004SRick Macklem retnum += NFSX_V4TIME;
30579ec7b004SRick Macklem break;
30589ec7b004SRick Macklem case NFSATTRBIT_TIMEMETADATA:
30599ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
30609ec7b004SRick Macklem txdr_nfsv4time(&vap->va_ctime, tl);
30619ec7b004SRick Macklem retnum += NFSX_V4TIME;
30629ec7b004SRick Macklem break;
30639ec7b004SRick Macklem case NFSATTRBIT_TIMEMODIFY:
30649ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
30659ec7b004SRick Macklem txdr_nfsv4time(&vap->va_mtime, tl);
30669ec7b004SRick Macklem retnum += NFSX_V4TIME;
30679ec7b004SRick Macklem break;
30683900c114SDoug Rabson case NFSATTRBIT_TIMECREATE:
30693900c114SDoug Rabson NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
30703900c114SDoug Rabson txdr_nfsv4time(&vap->va_birthtime, tl);
30713900c114SDoug Rabson retnum += NFSX_V4TIME;
30723900c114SDoug Rabson break;
30739ec7b004SRick Macklem case NFSATTRBIT_TIMEMODIFYSET:
30745055536eSJohn Baldwin if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
30759ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
30769ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
30779ec7b004SRick Macklem txdr_nfsv4time(&vap->va_mtime, tl);
30789ec7b004SRick Macklem retnum += NFSX_V4SETTIME;
30799ec7b004SRick Macklem } else {
30809ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
30819ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
30829ec7b004SRick Macklem retnum += NFSX_UNSIGNED;
30839ec7b004SRick Macklem }
30849ec7b004SRick Macklem break;
30859ec7b004SRick Macklem case NFSATTRBIT_MOUNTEDONFILEID:
30869ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
308707c0c166SRick Macklem if (at_root != 0)
308807c0c166SRick Macklem uquad = mounted_on_fileno;
30899ec7b004SRick Macklem else
309095ac7f1aSRick Macklem uquad = vap->va_fileid;
309107c0c166SRick Macklem txdr_hyper(uquad, tl);
30929ec7b004SRick Macklem retnum += NFSX_HYPER;
30939ec7b004SRick Macklem break;
3094c59e4cc3SRick Macklem case NFSATTRBIT_SUPPATTREXCLCREAT:
3095ea5776ecSRick Macklem NFSSETSUPP_ATTRBIT(&attrbits, nd);
3096ea5776ecSRick Macklem NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3097c59e4cc3SRick Macklem NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3098c59e4cc3SRick Macklem retnum += nfsrv_putattrbit(nd, &attrbits);
3099c59e4cc3SRick Macklem break;
310090d2dfabSRick Macklem case NFSATTRBIT_FSLAYOUTTYPE:
310190d2dfabSRick Macklem case NFSATTRBIT_LAYOUTTYPE:
310290d2dfabSRick Macklem if (nfsrv_devidcnt == 0)
310390d2dfabSRick Macklem siz = 1;
310490d2dfabSRick Macklem else
310590d2dfabSRick Macklem siz = 2;
310690d2dfabSRick Macklem if (siz == 2) {
310790d2dfabSRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
310890d2dfabSRick Macklem *tl++ = txdr_unsigned(1); /* One entry. */
310990d2dfabSRick Macklem if (nfsrv_doflexfile != 0 ||
311090d2dfabSRick Macklem nfsrv_maxpnfsmirror > 1)
311190d2dfabSRick Macklem *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
311290d2dfabSRick Macklem else
311390d2dfabSRick Macklem *tl = txdr_unsigned(
311490d2dfabSRick Macklem NFSLAYOUT_NFSV4_1_FILES);
311590d2dfabSRick Macklem } else {
311690d2dfabSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
311790d2dfabSRick Macklem *tl = 0;
311890d2dfabSRick Macklem }
311990d2dfabSRick Macklem retnum += siz * NFSX_UNSIGNED;
312090d2dfabSRick Macklem break;
312190d2dfabSRick Macklem case NFSATTRBIT_LAYOUTALIGNMENT:
312290d2dfabSRick Macklem case NFSATTRBIT_LAYOUTBLKSIZE:
312390d2dfabSRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3124ee29e6f3SRick Macklem *tl = txdr_unsigned(nfs_srvmaxio);
312590d2dfabSRick Macklem retnum += NFSX_UNSIGNED;
312690d2dfabSRick Macklem break;
3127c057a378SRick Macklem case NFSATTRBIT_XATTRSUPPORT:
3128c057a378SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3129c057a378SRick Macklem if (xattrsupp)
3130c057a378SRick Macklem *tl = newnfs_true;
3131c057a378SRick Macklem else
3132c057a378SRick Macklem *tl = newnfs_false;
3133c057a378SRick Macklem retnum += NFSX_UNSIGNED;
3134c057a378SRick Macklem break;
31352477e88bSRick Macklem case NFSATTRBIT_MODEUMASK:
31362477e88bSRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
31372477e88bSRick Macklem /*
31382477e88bSRick Macklem * Since FreeBSD applies the umask above the VFS/VOP,
31392477e88bSRick Macklem * there is no umask to handle here. If FreeBSD
31402477e88bSRick Macklem * moves handling of umask to below the VFS/VOP,
31412477e88bSRick Macklem * this could change.
31422477e88bSRick Macklem */
31432477e88bSRick Macklem *tl++ = vtonfsv34_mode(vap->va_mode);
31442477e88bSRick Macklem *tl = 0;
31452477e88bSRick Macklem retnum += 2 * NFSX_UNSIGNED;
31462477e88bSRick Macklem break;
3147709c1891SRick Macklem case NFSATTRBIT_CHANGEATTRTYPE:
3148709c1891SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3149709c1891SRick Macklem *tl = txdr_unsigned(NFSV4CHANGETYPE_UNDEFINED);
3150709c1891SRick Macklem if (mp != NULL) {
3151709c1891SRick Macklem if ((mp->mnt_vfc->vfc_flags &
3152709c1891SRick Macklem VFCF_FILEREVINC) != 0)
3153709c1891SRick Macklem *tl = txdr_unsigned(
3154709c1891SRick Macklem NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS);
3155709c1891SRick Macklem else if ((mp->mnt_vfc->vfc_flags &
3156709c1891SRick Macklem VFCF_FILEREVCT) != 0)
3157709c1891SRick Macklem *tl = txdr_unsigned(
3158709c1891SRick Macklem NFSV4CHANGETYPE_TIME_METADATA);
3159709c1891SRick Macklem }
3160709c1891SRick Macklem retnum += NFSX_UNSIGNED;
3161709c1891SRick Macklem break;
31629ec7b004SRick Macklem default:
31639ec7b004SRick Macklem printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
316474b8d63dSPedro F. Giffuni }
31659ec7b004SRick Macklem }
31669ec7b004SRick Macklem }
31679ec7b004SRick Macklem if (naclp != NULL)
31689ec7b004SRick Macklem acl_free(naclp);
31692f304845SKonstantin Belousov free(fs, M_STATFS);
31709ec7b004SRick Macklem *retnump = txdr_unsigned(retnum);
31719ec7b004SRick Macklem return (retnum + prefixnum);
31729ec7b004SRick Macklem }
31739ec7b004SRick Macklem
31749ec7b004SRick Macklem /*
31752d90ef47SRick Macklem * Calculate the files available attribute value.
31762d90ef47SRick Macklem */
31772d90ef47SRick Macklem static uint32_t
nfsv4_filesavail(struct statfs * fs,struct mount * mp)31782d90ef47SRick Macklem nfsv4_filesavail(struct statfs *fs, struct mount *mp)
31792d90ef47SRick Macklem {
31802d90ef47SRick Macklem uint32_t freenum;
31812d90ef47SRick Macklem #ifdef QUOTA
31822d90ef47SRick Macklem struct dqblk dqb;
31832d90ef47SRick Macklem uid_t savuid;
31842d90ef47SRick Macklem NFSPROC_T *p;
31852d90ef47SRick Macklem #endif
31862d90ef47SRick Macklem
31872d90ef47SRick Macklem /*
31882d90ef47SRick Macklem * Check quota and use min(quota, f_ffree).
31892d90ef47SRick Macklem */
31902d90ef47SRick Macklem freenum = fs->f_ffree;
31912d90ef47SRick Macklem #ifdef QUOTA
31922d90ef47SRick Macklem /*
31932d90ef47SRick Macklem * This is old OpenBSD code that does not build
31942d90ef47SRick Macklem * for FreeBSD. I do not know if doing this is
31952d90ef47SRick Macklem * useful, so I will just leave the code here.
31962d90ef47SRick Macklem */
31972d90ef47SRick Macklem p = curthread();
31982d90ef47SRick Macklem /*
31992d90ef47SRick Macklem * ufs_quotactl() insists that the uid argument
32002d90ef47SRick Macklem * equal p_ruid for non-root quota access, so
32012d90ef47SRick Macklem * we'll just make sure that's the case.
32022d90ef47SRick Macklem */
32032d90ef47SRick Macklem savuid = p->p_cred->p_ruid;
32042d90ef47SRick Macklem p->p_cred->p_ruid = cred->cr_uid;
32052d90ef47SRick Macklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
32062d90ef47SRick Macklem cred->cr_uid, &dqb))
32072d90ef47SRick Macklem freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
32082d90ef47SRick Macklem freenum);
32092d90ef47SRick Macklem p->p_cred->p_ruid = savuid;
32102d90ef47SRick Macklem #endif /* QUOTA */
32112d90ef47SRick Macklem return (freenum);
32122d90ef47SRick Macklem }
32132d90ef47SRick Macklem
32142d90ef47SRick Macklem /*
32159ec7b004SRick Macklem * Put the attribute bits onto an mbuf list.
32169ec7b004SRick Macklem * Return the number of bytes of output generated.
32179ec7b004SRick Macklem */
3218b9cc3262SRyan Moeller int
nfsrv_putattrbit(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp)32199ec7b004SRick Macklem nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
32209ec7b004SRick Macklem {
32219ec7b004SRick Macklem u_int32_t *tl;
32229ec7b004SRick Macklem int cnt, i, bytesize;
32239ec7b004SRick Macklem
32249ec7b004SRick Macklem for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
32259ec7b004SRick Macklem if (attrbitp->bits[cnt - 1])
32269ec7b004SRick Macklem break;
32279ec7b004SRick Macklem bytesize = (cnt + 1) * NFSX_UNSIGNED;
32289ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, bytesize);
32299ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt);
32309ec7b004SRick Macklem for (i = 0; i < cnt; i++)
32319ec7b004SRick Macklem *tl++ = txdr_unsigned(attrbitp->bits[i]);
32329ec7b004SRick Macklem return (bytesize);
32339ec7b004SRick Macklem }
32349ec7b004SRick Macklem
32359ec7b004SRick Macklem /*
3236f4179ad4SRick Macklem * Put the operation bits onto an mbuf list.
3237f4179ad4SRick Macklem * Return the number of bytes of output generated.
3238f4179ad4SRick Macklem */
3239f4179ad4SRick Macklem int
nfsrv_putopbit(struct nfsrv_descript * nd,nfsopbit_t * opbitp)3240f4179ad4SRick Macklem nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp)
3241f4179ad4SRick Macklem {
3242f4179ad4SRick Macklem uint32_t *tl;
3243f4179ad4SRick Macklem int cnt, i, bytesize;
3244f4179ad4SRick Macklem
3245f4179ad4SRick Macklem for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--)
3246f4179ad4SRick Macklem if (opbitp->bits[cnt - 1])
3247f4179ad4SRick Macklem break;
3248f4179ad4SRick Macklem bytesize = (cnt + 1) * NFSX_UNSIGNED;
3249f4179ad4SRick Macklem NFSM_BUILD(tl, uint32_t *, bytesize);
3250f4179ad4SRick Macklem *tl++ = txdr_unsigned(cnt);
3251f4179ad4SRick Macklem for (i = 0; i < cnt; i++)
3252f4179ad4SRick Macklem *tl++ = txdr_unsigned(opbitp->bits[i]);
3253f4179ad4SRick Macklem return (bytesize);
3254f4179ad4SRick Macklem }
3255f4179ad4SRick Macklem
3256f4179ad4SRick Macklem /*
32579ec7b004SRick Macklem * Convert a uid to a string.
32589ec7b004SRick Macklem * If the lookup fails, just output the digits.
32599ec7b004SRick Macklem * uid - the user id
32609ec7b004SRick Macklem * cpp - points to a buffer of size NFSV4_SMALLSTR
32619ec7b004SRick Macklem * (malloc a larger one, as required)
32629ec7b004SRick Macklem * retlenp - pointer to length to be returned
32639ec7b004SRick Macklem */
3264b9cc3262SRyan Moeller void
nfsv4_uidtostr(uid_t uid,u_char ** cpp,int * retlenp)32650f86b94aSEdward Tomasz Napierala nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
32669ec7b004SRick Macklem {
32679ec7b004SRick Macklem int i;
32689ec7b004SRick Macklem struct nfsusrgrp *usrp;
32699ec7b004SRick Macklem u_char *cp = *cpp;
32709ec7b004SRick Macklem uid_t tmp;
32719ec7b004SRick Macklem int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
327284be7e09SRick Macklem struct nfsrv_lughash *hp;
32739ec7b004SRick Macklem
3274f0db2b60SRick Macklem NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
32759ec7b004SRick Macklem cnt = 0;
32769ec7b004SRick Macklem tryagain:
3277f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3278f0db2b60SRick Macklem !NFSD_VNET(nfs_enable_uidtostring)) {
32799ec7b004SRick Macklem /*
32809ec7b004SRick Macklem * Always map nfsrv_defaultuid to "nobody".
32819ec7b004SRick Macklem */
3282f0db2b60SRick Macklem if (uid == NFSD_VNET(nfsrv_defaultuid)) {
3283f0db2b60SRick Macklem i = NFSD_VNET(nfsrv_dnsnamelen) + 7;
32849ec7b004SRick Macklem if (i > len) {
32859ec7b004SRick Macklem if (len > NFSV4_SMALLSTR)
32869ec7b004SRick Macklem free(cp, M_NFSSTRING);
32879ec7b004SRick Macklem cp = malloc(i, M_NFSSTRING, M_WAITOK);
32889ec7b004SRick Macklem *cpp = cp;
32899ec7b004SRick Macklem len = i;
32909ec7b004SRick Macklem goto tryagain;
32919ec7b004SRick Macklem }
32929ec7b004SRick Macklem *retlenp = i;
32939ec7b004SRick Macklem NFSBCOPY("nobody@", cp, 7);
32949ec7b004SRick Macklem cp += 7;
3295f0db2b60SRick Macklem NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3296f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsnamelen));
3297f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
32989ec7b004SRick Macklem return;
32999ec7b004SRick Macklem }
33009ec7b004SRick Macklem hasampersand = 0;
330184be7e09SRick Macklem hp = NFSUSERHASH(uid);
330284be7e09SRick Macklem mtx_lock(&hp->mtx);
330384be7e09SRick Macklem TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
33049ec7b004SRick Macklem if (usrp->lug_uid == uid) {
33059ec7b004SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
33069ec7b004SRick Macklem break;
33079ec7b004SRick Macklem /*
33089ec7b004SRick Macklem * If the name doesn't already have an '@'
33099ec7b004SRick Macklem * in it, append @domainname to it.
33109ec7b004SRick Macklem */
33119ec7b004SRick Macklem for (i = 0; i < usrp->lug_namelen; i++) {
33129ec7b004SRick Macklem if (usrp->lug_name[i] == '@') {
33139ec7b004SRick Macklem hasampersand = 1;
33149ec7b004SRick Macklem break;
33159ec7b004SRick Macklem }
33169ec7b004SRick Macklem }
33179ec7b004SRick Macklem if (hasampersand)
33189ec7b004SRick Macklem i = usrp->lug_namelen;
33199ec7b004SRick Macklem else
33209ec7b004SRick Macklem i = usrp->lug_namelen +
3321f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsnamelen) + 1;
33229ec7b004SRick Macklem if (i > len) {
332384be7e09SRick Macklem mtx_unlock(&hp->mtx);
33249ec7b004SRick Macklem if (len > NFSV4_SMALLSTR)
33259ec7b004SRick Macklem free(cp, M_NFSSTRING);
33269ec7b004SRick Macklem cp = malloc(i, M_NFSSTRING, M_WAITOK);
33279ec7b004SRick Macklem *cpp = cp;
33289ec7b004SRick Macklem len = i;
33299ec7b004SRick Macklem goto tryagain;
33309ec7b004SRick Macklem }
33319ec7b004SRick Macklem *retlenp = i;
33329ec7b004SRick Macklem NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
33339ec7b004SRick Macklem if (!hasampersand) {
33349ec7b004SRick Macklem cp += usrp->lug_namelen;
33359ec7b004SRick Macklem *cp++ = '@';
3336f0db2b60SRick Macklem NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3337f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsnamelen));
33389ec7b004SRick Macklem }
333984be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
334084be7e09SRick Macklem TAILQ_INSERT_TAIL(&hp->lughead, usrp,
334184be7e09SRick Macklem lug_numhash);
334284be7e09SRick Macklem mtx_unlock(&hp->mtx);
3343f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
33449ec7b004SRick Macklem return;
33459ec7b004SRick Macklem }
33469ec7b004SRick Macklem }
334784be7e09SRick Macklem mtx_unlock(&hp->mtx);
33489ec7b004SRick Macklem cnt++;
3349f32bf292SEdward Tomasz Napierala ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
33509ec7b004SRick Macklem if (ret == 0 && cnt < 2)
33519ec7b004SRick Macklem goto tryagain;
33529ec7b004SRick Macklem }
33539ec7b004SRick Macklem
33549ec7b004SRick Macklem /*
33559ec7b004SRick Macklem * No match, just return a string of digits.
33569ec7b004SRick Macklem */
33579ec7b004SRick Macklem tmp = uid;
33589ec7b004SRick Macklem i = 0;
33599ec7b004SRick Macklem while (tmp || i == 0) {
33609ec7b004SRick Macklem tmp /= 10;
33619ec7b004SRick Macklem i++;
33629ec7b004SRick Macklem }
33639ec7b004SRick Macklem len = (i > len) ? len : i;
33649ec7b004SRick Macklem *retlenp = len;
33659ec7b004SRick Macklem cp += (len - 1);
33669ec7b004SRick Macklem tmp = uid;
33679ec7b004SRick Macklem for (i = 0; i < len; i++) {
33689ec7b004SRick Macklem *cp-- = '0' + (tmp % 10);
33699ec7b004SRick Macklem tmp /= 10;
33709ec7b004SRick Macklem }
3371f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
33729ec7b004SRick Macklem return;
33739ec7b004SRick Macklem }
33749ec7b004SRick Macklem
33759ec7b004SRick Macklem /*
337684be7e09SRick Macklem * Get a credential for the uid with the server's group list.
337784be7e09SRick Macklem * If none is found, just return the credential passed in after
337884be7e09SRick Macklem * logging a warning message.
337984be7e09SRick Macklem */
338084be7e09SRick Macklem struct ucred *
nfsrv_getgrpscred(struct ucred * oldcred)338184be7e09SRick Macklem nfsrv_getgrpscred(struct ucred *oldcred)
338284be7e09SRick Macklem {
338384be7e09SRick Macklem struct nfsusrgrp *usrp;
338484be7e09SRick Macklem struct ucred *newcred;
338584be7e09SRick Macklem int cnt, ret;
338684be7e09SRick Macklem uid_t uid;
338784be7e09SRick Macklem struct nfsrv_lughash *hp;
338884be7e09SRick Macklem
338984be7e09SRick Macklem cnt = 0;
339084be7e09SRick Macklem uid = oldcred->cr_uid;
339184be7e09SRick Macklem tryagain:
3392f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
339384be7e09SRick Macklem hp = NFSUSERHASH(uid);
339484be7e09SRick Macklem mtx_lock(&hp->mtx);
339584be7e09SRick Macklem TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
339684be7e09SRick Macklem if (usrp->lug_uid == uid) {
339784be7e09SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
339884be7e09SRick Macklem break;
339984be7e09SRick Macklem if (usrp->lug_cred != NULL) {
340084be7e09SRick Macklem newcred = crhold(usrp->lug_cred);
340184be7e09SRick Macklem crfree(oldcred);
340284be7e09SRick Macklem } else
340384be7e09SRick Macklem newcred = oldcred;
340484be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
340584be7e09SRick Macklem TAILQ_INSERT_TAIL(&hp->lughead, usrp,
340684be7e09SRick Macklem lug_numhash);
340784be7e09SRick Macklem mtx_unlock(&hp->mtx);
340884be7e09SRick Macklem return (newcred);
340984be7e09SRick Macklem }
341084be7e09SRick Macklem }
341184be7e09SRick Macklem mtx_unlock(&hp->mtx);
341284be7e09SRick Macklem cnt++;
3413f32bf292SEdward Tomasz Napierala ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
341484be7e09SRick Macklem if (ret == 0 && cnt < 2)
341584be7e09SRick Macklem goto tryagain;
341684be7e09SRick Macklem }
341784be7e09SRick Macklem return (oldcred);
341884be7e09SRick Macklem }
341984be7e09SRick Macklem
342084be7e09SRick Macklem /*
34219ec7b004SRick Macklem * Convert a string to a uid.
34229ec7b004SRick Macklem * If no conversion is possible return NFSERR_BADOWNER, otherwise
34239ec7b004SRick Macklem * return 0.
3424c52005a3SRick Macklem * If this is called from a client side mount using AUTH_SYS and the
3425c52005a3SRick Macklem * string is made up entirely of digits, just convert the string to
3426c52005a3SRick Macklem * a number.
34279ec7b004SRick Macklem */
3428b9cc3262SRyan Moeller int
nfsv4_strtouid(struct nfsrv_descript * nd,u_char * str,int len,uid_t * uidp)34290658ac39SEdward Tomasz Napierala nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
34309ec7b004SRick Macklem {
34319ec7b004SRick Macklem int i;
3432c52005a3SRick Macklem char *cp, *endstr, *str0;
34339ec7b004SRick Macklem struct nfsusrgrp *usrp;
34349ec7b004SRick Macklem int cnt, ret;
3435a9285ae5SZack Kirsch int error = 0;
3436c52005a3SRick Macklem uid_t tuid;
343784be7e09SRick Macklem struct nfsrv_lughash *hp, *hp2;
34389ec7b004SRick Macklem
3439f0db2b60SRick Macklem NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3440a9285ae5SZack Kirsch if (len == 0) {
3441a9285ae5SZack Kirsch error = NFSERR_BADOWNER;
3442a9285ae5SZack Kirsch goto out;
3443a9285ae5SZack Kirsch }
3444c52005a3SRick Macklem /* If a string of digits and an AUTH_SYS mount, just convert it. */
3445c52005a3SRick Macklem str0 = str;
3446c52005a3SRick Macklem tuid = (uid_t)strtoul(str0, &endstr, 10);
3447ca20bd92SRick Macklem if ((endstr - str0) == len) {
3448ca20bd92SRick Macklem /* A numeric string. */
3449ca20bd92SRick Macklem if ((nd->nd_flag & ND_KERBV) == 0 &&
3450ca20bd92SRick Macklem ((nd->nd_flag & ND_NFSCL) != 0 ||
3451f0db2b60SRick Macklem NFSD_VNET(nfsd_enable_stringtouid) != 0))
3452c52005a3SRick Macklem *uidp = tuid;
3453ca20bd92SRick Macklem else
3454ca20bd92SRick Macklem error = NFSERR_BADOWNER;
3455c52005a3SRick Macklem goto out;
3456c52005a3SRick Macklem }
34579ec7b004SRick Macklem /*
34589ec7b004SRick Macklem * Look for an '@'.
34599ec7b004SRick Macklem */
3460c52005a3SRick Macklem cp = strchr(str0, '@');
3461c52005a3SRick Macklem if (cp != NULL)
3462c52005a3SRick Macklem i = (int)(cp++ - str0);
3463c52005a3SRick Macklem else
3464c52005a3SRick Macklem i = len;
34659ec7b004SRick Macklem
34669ec7b004SRick Macklem cnt = 0;
34679ec7b004SRick Macklem tryagain:
3468f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
34699ec7b004SRick Macklem /*
347084be7e09SRick Macklem * If an '@' is found and the domain name matches, search for
347184be7e09SRick Macklem * the name with dns stripped off.
34720347ddf4SRick Macklem * The match for alphabetics in now case insensitive,
34730347ddf4SRick Macklem * since RFC8881 defines this string as a DNS domain name.
34749ec7b004SRick Macklem */
347584be7e09SRick Macklem if (cnt == 0 && i < len && i > 0 &&
3476f0db2b60SRick Macklem (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
34770347ddf4SRick Macklem strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
34780347ddf4SRick Macklem NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3479f0db2b60SRick Macklem len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
34809ec7b004SRick Macklem *(cp - 1) = '\0';
34819ec7b004SRick Macklem }
34829ec7b004SRick Macklem
34839ec7b004SRick Macklem /*
34849ec7b004SRick Macklem * Check for the special case of "nobody".
34859ec7b004SRick Macklem */
34869ec7b004SRick Macklem if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3487f0db2b60SRick Macklem *uidp = NFSD_VNET(nfsrv_defaultuid);
3488a9285ae5SZack Kirsch error = 0;
3489a9285ae5SZack Kirsch goto out;
34909ec7b004SRick Macklem }
34919ec7b004SRick Macklem
349284be7e09SRick Macklem hp = NFSUSERNAMEHASH(str, len);
349384be7e09SRick Macklem mtx_lock(&hp->mtx);
349484be7e09SRick Macklem TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
34959ec7b004SRick Macklem if (usrp->lug_namelen == len &&
34969ec7b004SRick Macklem !NFSBCMP(usrp->lug_name, str, len)) {
34979ec7b004SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
34989ec7b004SRick Macklem break;
349984be7e09SRick Macklem hp2 = NFSUSERHASH(usrp->lug_uid);
350084be7e09SRick Macklem mtx_lock(&hp2->mtx);
350184be7e09SRick Macklem TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
350284be7e09SRick Macklem TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
350384be7e09SRick Macklem lug_numhash);
35049ec7b004SRick Macklem *uidp = usrp->lug_uid;
350584be7e09SRick Macklem mtx_unlock(&hp2->mtx);
350684be7e09SRick Macklem mtx_unlock(&hp->mtx);
3507a9285ae5SZack Kirsch error = 0;
3508a9285ae5SZack Kirsch goto out;
35099ec7b004SRick Macklem }
35109ec7b004SRick Macklem }
351184be7e09SRick Macklem mtx_unlock(&hp->mtx);
35129ec7b004SRick Macklem cnt++;
35139ec7b004SRick Macklem ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3514f32bf292SEdward Tomasz Napierala str);
35159ec7b004SRick Macklem if (ret == 0 && cnt < 2)
35169ec7b004SRick Macklem goto tryagain;
351784be7e09SRick Macklem }
3518a9285ae5SZack Kirsch error = NFSERR_BADOWNER;
3519a9285ae5SZack Kirsch
3520a9285ae5SZack Kirsch out:
3521f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
3522a9285ae5SZack Kirsch NFSEXITCODE(error);
3523a9285ae5SZack Kirsch return (error);
35249ec7b004SRick Macklem }
35259ec7b004SRick Macklem
35269ec7b004SRick Macklem /*
35279ec7b004SRick Macklem * Convert a gid to a string.
35289ec7b004SRick Macklem * gid - the group id
35299ec7b004SRick Macklem * cpp - points to a buffer of size NFSV4_SMALLSTR
35309ec7b004SRick Macklem * (malloc a larger one, as required)
35319ec7b004SRick Macklem * retlenp - pointer to length to be returned
35329ec7b004SRick Macklem */
3533b9cc3262SRyan Moeller void
nfsv4_gidtostr(gid_t gid,u_char ** cpp,int * retlenp)3534c703cba8SEdward Tomasz Napierala nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
35359ec7b004SRick Macklem {
35369ec7b004SRick Macklem int i;
35379ec7b004SRick Macklem struct nfsusrgrp *usrp;
35389ec7b004SRick Macklem u_char *cp = *cpp;
35399ec7b004SRick Macklem gid_t tmp;
35409ec7b004SRick Macklem int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
354184be7e09SRick Macklem struct nfsrv_lughash *hp;
35429ec7b004SRick Macklem
3543f0db2b60SRick Macklem NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
35449ec7b004SRick Macklem cnt = 0;
35459ec7b004SRick Macklem tryagain:
3546f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3547f0db2b60SRick Macklem !NFSD_VNET(nfs_enable_uidtostring)) {
35489ec7b004SRick Macklem /*
35499ec7b004SRick Macklem * Always map nfsrv_defaultgid to "nogroup".
35509ec7b004SRick Macklem */
3551f0db2b60SRick Macklem if (gid == NFSD_VNET(nfsrv_defaultgid)) {
3552f0db2b60SRick Macklem i = NFSD_VNET(nfsrv_dnsnamelen) + 8;
35539ec7b004SRick Macklem if (i > len) {
35549ec7b004SRick Macklem if (len > NFSV4_SMALLSTR)
35559ec7b004SRick Macklem free(cp, M_NFSSTRING);
35569ec7b004SRick Macklem cp = malloc(i, M_NFSSTRING, M_WAITOK);
35579ec7b004SRick Macklem *cpp = cp;
35589ec7b004SRick Macklem len = i;
35599ec7b004SRick Macklem goto tryagain;
35609ec7b004SRick Macklem }
35619ec7b004SRick Macklem *retlenp = i;
35629ec7b004SRick Macklem NFSBCOPY("nogroup@", cp, 8);
35639ec7b004SRick Macklem cp += 8;
3564f0db2b60SRick Macklem NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3565f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsnamelen));
3566f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
35679ec7b004SRick Macklem return;
35689ec7b004SRick Macklem }
35699ec7b004SRick Macklem hasampersand = 0;
357084be7e09SRick Macklem hp = NFSGROUPHASH(gid);
357184be7e09SRick Macklem mtx_lock(&hp->mtx);
357284be7e09SRick Macklem TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
35739ec7b004SRick Macklem if (usrp->lug_gid == gid) {
35749ec7b004SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
35759ec7b004SRick Macklem break;
35769ec7b004SRick Macklem /*
35779ec7b004SRick Macklem * If the name doesn't already have an '@'
35789ec7b004SRick Macklem * in it, append @domainname to it.
35799ec7b004SRick Macklem */
35809ec7b004SRick Macklem for (i = 0; i < usrp->lug_namelen; i++) {
35819ec7b004SRick Macklem if (usrp->lug_name[i] == '@') {
35829ec7b004SRick Macklem hasampersand = 1;
35839ec7b004SRick Macklem break;
35849ec7b004SRick Macklem }
35859ec7b004SRick Macklem }
35869ec7b004SRick Macklem if (hasampersand)
35879ec7b004SRick Macklem i = usrp->lug_namelen;
35889ec7b004SRick Macklem else
35899ec7b004SRick Macklem i = usrp->lug_namelen +
3590f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsnamelen) + 1;
35919ec7b004SRick Macklem if (i > len) {
359284be7e09SRick Macklem mtx_unlock(&hp->mtx);
35939ec7b004SRick Macklem if (len > NFSV4_SMALLSTR)
35949ec7b004SRick Macklem free(cp, M_NFSSTRING);
35959ec7b004SRick Macklem cp = malloc(i, M_NFSSTRING, M_WAITOK);
35969ec7b004SRick Macklem *cpp = cp;
35979ec7b004SRick Macklem len = i;
35989ec7b004SRick Macklem goto tryagain;
35999ec7b004SRick Macklem }
36009ec7b004SRick Macklem *retlenp = i;
36019ec7b004SRick Macklem NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
36029ec7b004SRick Macklem if (!hasampersand) {
36039ec7b004SRick Macklem cp += usrp->lug_namelen;
36049ec7b004SRick Macklem *cp++ = '@';
3605f0db2b60SRick Macklem NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3606f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsnamelen));
36079ec7b004SRick Macklem }
360884be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
360984be7e09SRick Macklem TAILQ_INSERT_TAIL(&hp->lughead, usrp,
361084be7e09SRick Macklem lug_numhash);
361184be7e09SRick Macklem mtx_unlock(&hp->mtx);
3612f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
36139ec7b004SRick Macklem return;
36149ec7b004SRick Macklem }
36159ec7b004SRick Macklem }
361684be7e09SRick Macklem mtx_unlock(&hp->mtx);
36179ec7b004SRick Macklem cnt++;
3618f32bf292SEdward Tomasz Napierala ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
36199ec7b004SRick Macklem if (ret == 0 && cnt < 2)
36209ec7b004SRick Macklem goto tryagain;
36219ec7b004SRick Macklem }
36229ec7b004SRick Macklem
36239ec7b004SRick Macklem /*
36249ec7b004SRick Macklem * No match, just return a string of digits.
36259ec7b004SRick Macklem */
36269ec7b004SRick Macklem tmp = gid;
36279ec7b004SRick Macklem i = 0;
36289ec7b004SRick Macklem while (tmp || i == 0) {
36299ec7b004SRick Macklem tmp /= 10;
36309ec7b004SRick Macklem i++;
36319ec7b004SRick Macklem }
36329ec7b004SRick Macklem len = (i > len) ? len : i;
36339ec7b004SRick Macklem *retlenp = len;
36349ec7b004SRick Macklem cp += (len - 1);
36359ec7b004SRick Macklem tmp = gid;
36369ec7b004SRick Macklem for (i = 0; i < len; i++) {
36379ec7b004SRick Macklem *cp-- = '0' + (tmp % 10);
36389ec7b004SRick Macklem tmp /= 10;
36399ec7b004SRick Macklem }
3640f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
36419ec7b004SRick Macklem return;
36429ec7b004SRick Macklem }
36439ec7b004SRick Macklem
36449ec7b004SRick Macklem /*
36459ec7b004SRick Macklem * Convert a string to a gid.
3646c52005a3SRick Macklem * If no conversion is possible return NFSERR_BADOWNER, otherwise
3647c52005a3SRick Macklem * return 0.
3648c52005a3SRick Macklem * If this is called from a client side mount using AUTH_SYS and the
3649c52005a3SRick Macklem * string is made up entirely of digits, just convert the string to
3650c52005a3SRick Macklem * a number.
36519ec7b004SRick Macklem */
3652b9cc3262SRyan Moeller int
nfsv4_strtogid(struct nfsrv_descript * nd,u_char * str,int len,gid_t * gidp)36532df8bd90SEdward Tomasz Napierala nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
36549ec7b004SRick Macklem {
36559ec7b004SRick Macklem int i;
3656c52005a3SRick Macklem char *cp, *endstr, *str0;
36579ec7b004SRick Macklem struct nfsusrgrp *usrp;
36589ec7b004SRick Macklem int cnt, ret;
3659a9285ae5SZack Kirsch int error = 0;
3660c52005a3SRick Macklem gid_t tgid;
366184be7e09SRick Macklem struct nfsrv_lughash *hp, *hp2;
36629ec7b004SRick Macklem
3663f0db2b60SRick Macklem NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3664a9285ae5SZack Kirsch if (len == 0) {
3665a9285ae5SZack Kirsch error = NFSERR_BADOWNER;
3666a9285ae5SZack Kirsch goto out;
3667a9285ae5SZack Kirsch }
3668c52005a3SRick Macklem /* If a string of digits and an AUTH_SYS mount, just convert it. */
3669c52005a3SRick Macklem str0 = str;
3670c52005a3SRick Macklem tgid = (gid_t)strtoul(str0, &endstr, 10);
3671ca20bd92SRick Macklem if ((endstr - str0) == len) {
3672ca20bd92SRick Macklem /* A numeric string. */
3673ca20bd92SRick Macklem if ((nd->nd_flag & ND_KERBV) == 0 &&
3674ca20bd92SRick Macklem ((nd->nd_flag & ND_NFSCL) != 0 ||
3675f0db2b60SRick Macklem NFSD_VNET(nfsd_enable_stringtouid) != 0))
3676c52005a3SRick Macklem *gidp = tgid;
3677ca20bd92SRick Macklem else
3678ca20bd92SRick Macklem error = NFSERR_BADOWNER;
3679c52005a3SRick Macklem goto out;
3680c52005a3SRick Macklem }
36819ec7b004SRick Macklem /*
36829ec7b004SRick Macklem * Look for an '@'.
36839ec7b004SRick Macklem */
3684c52005a3SRick Macklem cp = strchr(str0, '@');
3685c52005a3SRick Macklem if (cp != NULL)
3686c52005a3SRick Macklem i = (int)(cp++ - str0);
3687c52005a3SRick Macklem else
3688c52005a3SRick Macklem i = len;
36899ec7b004SRick Macklem
36909ec7b004SRick Macklem cnt = 0;
36919ec7b004SRick Macklem tryagain:
3692f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
36939ec7b004SRick Macklem /*
369484be7e09SRick Macklem * If an '@' is found and the dns name matches, search for the
369584be7e09SRick Macklem * name with the dns stripped off.
36969ec7b004SRick Macklem */
369784be7e09SRick Macklem if (cnt == 0 && i < len && i > 0 &&
3698f0db2b60SRick Macklem (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
36990347ddf4SRick Macklem strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
37000347ddf4SRick Macklem NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3701f0db2b60SRick Macklem len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
37029ec7b004SRick Macklem *(cp - 1) = '\0';
37039ec7b004SRick Macklem }
37049ec7b004SRick Macklem
37059ec7b004SRick Macklem /*
37069ec7b004SRick Macklem * Check for the special case of "nogroup".
37079ec7b004SRick Macklem */
37089ec7b004SRick Macklem if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3709f0db2b60SRick Macklem *gidp = NFSD_VNET(nfsrv_defaultgid);
3710a9285ae5SZack Kirsch error = 0;
3711a9285ae5SZack Kirsch goto out;
37129ec7b004SRick Macklem }
37139ec7b004SRick Macklem
371484be7e09SRick Macklem hp = NFSGROUPNAMEHASH(str, len);
371584be7e09SRick Macklem mtx_lock(&hp->mtx);
371684be7e09SRick Macklem TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
37179ec7b004SRick Macklem if (usrp->lug_namelen == len &&
37189ec7b004SRick Macklem !NFSBCMP(usrp->lug_name, str, len)) {
37199ec7b004SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
37209ec7b004SRick Macklem break;
372184be7e09SRick Macklem hp2 = NFSGROUPHASH(usrp->lug_gid);
372284be7e09SRick Macklem mtx_lock(&hp2->mtx);
372384be7e09SRick Macklem TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
372484be7e09SRick Macklem TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
372584be7e09SRick Macklem lug_numhash);
37269ec7b004SRick Macklem *gidp = usrp->lug_gid;
372784be7e09SRick Macklem mtx_unlock(&hp2->mtx);
372884be7e09SRick Macklem mtx_unlock(&hp->mtx);
3729a9285ae5SZack Kirsch error = 0;
3730a9285ae5SZack Kirsch goto out;
37319ec7b004SRick Macklem }
37329ec7b004SRick Macklem }
373384be7e09SRick Macklem mtx_unlock(&hp->mtx);
37349ec7b004SRick Macklem cnt++;
37359ec7b004SRick Macklem ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3736f32bf292SEdward Tomasz Napierala str);
37379ec7b004SRick Macklem if (ret == 0 && cnt < 2)
37389ec7b004SRick Macklem goto tryagain;
373984be7e09SRick Macklem }
3740a9285ae5SZack Kirsch error = NFSERR_BADOWNER;
3741a9285ae5SZack Kirsch
3742a9285ae5SZack Kirsch out:
3743f0db2b60SRick Macklem NFSD_CURVNET_RESTORE();
3744a9285ae5SZack Kirsch NFSEXITCODE(error);
3745a9285ae5SZack Kirsch return (error);
37469ec7b004SRick Macklem }
37479ec7b004SRick Macklem
37489ec7b004SRick Macklem /*
37499ec7b004SRick Macklem * Set the port for the nfsuserd.
37509ec7b004SRick Macklem */
3751b9cc3262SRyan Moeller int
nfsrv_nfsuserdport(struct nfsuserd_args * nargs,NFSPROC_T * p)375280405bcfSRick Macklem nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
37539ec7b004SRick Macklem {
37549ec7b004SRick Macklem struct nfssockreq *rp;
375580405bcfSRick Macklem #ifdef INET
37569ec7b004SRick Macklem struct sockaddr_in *ad;
375780405bcfSRick Macklem #endif
375880405bcfSRick Macklem #ifdef INET6
375980405bcfSRick Macklem struct sockaddr_in6 *ad6;
376080405bcfSRick Macklem const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
376180405bcfSRick Macklem #endif
37629ec7b004SRick Macklem int error;
37639ec7b004SRick Macklem
37649ec7b004SRick Macklem NFSLOCKNAMEID();
3765f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) {
37669ec7b004SRick Macklem NFSUNLOCKNAMEID();
3767a9285ae5SZack Kirsch error = EPERM;
3768a9285ae5SZack Kirsch goto out;
37699ec7b004SRick Macklem }
3770f0db2b60SRick Macklem NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
37719ec7b004SRick Macklem /*
37729ec7b004SRick Macklem * Set up the socket record and connect.
3773e1cda5eeSRick Macklem * Set nr_client NULL before unlocking, just to ensure that no other
3774e1cda5eeSRick Macklem * process/thread/core will use a bogus old value. This could only
3775e1cda5eeSRick Macklem * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3776e1cda5eeSRick Macklem * broken.
37779ec7b004SRick Macklem */
3778f0db2b60SRick Macklem rp = &NFSD_VNET(nfsrv_nfsuserdsock);
37799ec7b004SRick Macklem rp->nr_client = NULL;
3780e1cda5eeSRick Macklem NFSUNLOCKNAMEID();
37819ec7b004SRick Macklem rp->nr_sotype = SOCK_DGRAM;
37829ec7b004SRick Macklem rp->nr_soproto = IPPROTO_UDP;
378302c8dd7dSRick Macklem rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
378402c8dd7dSRick Macklem rp->nr_cred = NULL;
37859ec7b004SRick Macklem rp->nr_prog = RPCPROG_NFSUSERD;
378680405bcfSRick Macklem error = 0;
378780405bcfSRick Macklem switch (nargs->nuserd_family) {
378880405bcfSRick Macklem #ifdef INET
378980405bcfSRick Macklem case AF_INET:
379080405bcfSRick Macklem rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
379180405bcfSRick Macklem M_WAITOK | M_ZERO);
379280405bcfSRick Macklem ad = (struct sockaddr_in *)rp->nr_nam;
379380405bcfSRick Macklem ad->sin_len = sizeof(struct sockaddr_in);
379480405bcfSRick Macklem ad->sin_family = AF_INET;
379580405bcfSRick Macklem ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
379680405bcfSRick Macklem ad->sin_port = nargs->nuserd_port;
379780405bcfSRick Macklem break;
379880405bcfSRick Macklem #endif
379980405bcfSRick Macklem #ifdef INET6
380080405bcfSRick Macklem case AF_INET6:
380180405bcfSRick Macklem rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
380280405bcfSRick Macklem M_WAITOK | M_ZERO);
380380405bcfSRick Macklem ad6 = (struct sockaddr_in6 *)rp->nr_nam;
380480405bcfSRick Macklem ad6->sin6_len = sizeof(struct sockaddr_in6);
380580405bcfSRick Macklem ad6->sin6_family = AF_INET6;
380680405bcfSRick Macklem ad6->sin6_addr = in6loopback;
380780405bcfSRick Macklem ad6->sin6_port = nargs->nuserd_port;
380880405bcfSRick Macklem break;
380980405bcfSRick Macklem #endif
381080405bcfSRick Macklem default:
381180405bcfSRick Macklem error = ENXIO;
381280405bcfSRick Macklem }
38139ec7b004SRick Macklem rp->nr_vers = RPCNFSUSERD_VERS;
381480405bcfSRick Macklem if (error == 0)
38151e0a518dSRick Macklem error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
38161e0a518dSRick Macklem &rp->nr_client);
3817e1cda5eeSRick Macklem if (error == 0) {
3818e1cda5eeSRick Macklem NFSLOCKNAMEID();
3819f0db2b60SRick Macklem NFSD_VNET(nfsrv_nfsuserd) = RUNNING;
3820e1cda5eeSRick Macklem NFSUNLOCKNAMEID();
3821e1cda5eeSRick Macklem } else {
3822b97b91b5SConrad Meyer free(rp->nr_nam, M_SONAME);
3823e1cda5eeSRick Macklem NFSLOCKNAMEID();
3824f0db2b60SRick Macklem NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3825e1cda5eeSRick Macklem NFSUNLOCKNAMEID();
38269ec7b004SRick Macklem }
3827a9285ae5SZack Kirsch out:
3828a9285ae5SZack Kirsch NFSEXITCODE(error);
38299ec7b004SRick Macklem return (error);
38309ec7b004SRick Macklem }
38319ec7b004SRick Macklem
38329ec7b004SRick Macklem /*
38339ec7b004SRick Macklem * Delete the nfsuserd port.
38349ec7b004SRick Macklem */
3835b9cc3262SRyan Moeller void
nfsrv_nfsuserddelport(void)38369ec7b004SRick Macklem nfsrv_nfsuserddelport(void)
38379ec7b004SRick Macklem {
38389ec7b004SRick Macklem
38399ec7b004SRick Macklem NFSLOCKNAMEID();
3840f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
38419ec7b004SRick Macklem NFSUNLOCKNAMEID();
38429ec7b004SRick Macklem return;
38439ec7b004SRick Macklem }
3844f0db2b60SRick Macklem NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3845e1cda5eeSRick Macklem /* Wait for all upcalls to complete. */
3846f0db2b60SRick Macklem while (NFSD_VNET(nfsrv_userdupcalls) > 0)
3847f0db2b60SRick Macklem msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS,
3848e1cda5eeSRick Macklem "nfsupcalls", 0);
38499ec7b004SRick Macklem NFSUNLOCKNAMEID();
3850f0db2b60SRick Macklem newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock));
3851f0db2b60SRick Macklem free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME);
3852e1cda5eeSRick Macklem NFSLOCKNAMEID();
3853f0db2b60SRick Macklem NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3854e1cda5eeSRick Macklem NFSUNLOCKNAMEID();
38559ec7b004SRick Macklem }
38569ec7b004SRick Macklem
38579ec7b004SRick Macklem /*
38589ec7b004SRick Macklem * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
38599ec7b004SRick Macklem * name<-->id cache.
38609ec7b004SRick Macklem * Returns 0 upon success, non-zero otherwise.
38619ec7b004SRick Macklem */
38629ec7b004SRick Macklem static int
nfsrv_getuser(int procnum,uid_t uid,gid_t gid,char * name)3863f32bf292SEdward Tomasz Napierala nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
38649ec7b004SRick Macklem {
38659ec7b004SRick Macklem u_int32_t *tl;
38669ec7b004SRick Macklem struct nfsrv_descript *nd;
38679ec7b004SRick Macklem int len;
38689ec7b004SRick Macklem struct nfsrv_descript nfsd;
38699ec7b004SRick Macklem struct ucred *cred;
38709ec7b004SRick Macklem int error;
38719ec7b004SRick Macklem
38729ec7b004SRick Macklem NFSLOCKNAMEID();
3873f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
38749ec7b004SRick Macklem NFSUNLOCKNAMEID();
3875a9285ae5SZack Kirsch error = EPERM;
3876a9285ae5SZack Kirsch goto out;
38779ec7b004SRick Macklem }
3878e1cda5eeSRick Macklem /*
3879e1cda5eeSRick Macklem * Maintain a count of upcalls in progress, so that nfsrv_X()
3880e1cda5eeSRick Macklem * can wait until no upcalls are in progress.
3881e1cda5eeSRick Macklem */
3882f0db2b60SRick Macklem NFSD_VNET(nfsrv_userdupcalls)++;
38839ec7b004SRick Macklem NFSUNLOCKNAMEID();
3884f0db2b60SRick Macklem KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0,
3885e1cda5eeSRick Macklem ("nfsrv_getuser: non-positive upcalls"));
38869ec7b004SRick Macklem nd = &nfsd;
38879ec7b004SRick Macklem cred = newnfs_getcred();
38889ec7b004SRick Macklem nd->nd_flag = ND_GSSINITREPLY;
38899ec7b004SRick Macklem nfsrvd_rephead(nd);
38909ec7b004SRick Macklem
38919ec7b004SRick Macklem nd->nd_procnum = procnum;
38929ec7b004SRick Macklem if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
38939ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
38949ec7b004SRick Macklem if (procnum == RPCNFSUSERD_GETUID)
38959ec7b004SRick Macklem *tl = txdr_unsigned(uid);
38969ec7b004SRick Macklem else
38979ec7b004SRick Macklem *tl = txdr_unsigned(gid);
38989ec7b004SRick Macklem } else {
38999ec7b004SRick Macklem len = strlen(name);
39009ec7b004SRick Macklem (void) nfsm_strtom(nd, name, len);
39019ec7b004SRick Macklem }
3902f0db2b60SRick Macklem error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock),
3903f0db2b60SRick Macklem NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0,
3904f0db2b60SRick Macklem NULL, NULL);
3905e1cda5eeSRick Macklem NFSLOCKNAMEID();
3906f0db2b60SRick Macklem if (--NFSD_VNET(nfsrv_userdupcalls) == 0 &&
3907f0db2b60SRick Macklem NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP)
3908f0db2b60SRick Macklem wakeup(&NFSD_VNET(nfsrv_userdupcalls));
3909e1cda5eeSRick Macklem NFSUNLOCKNAMEID();
39109ec7b004SRick Macklem NFSFREECRED(cred);
39119ec7b004SRick Macklem if (!error) {
3912c948a17aSRick Macklem m_freem(nd->nd_mrep);
39139ec7b004SRick Macklem error = nd->nd_repstat;
39149ec7b004SRick Macklem }
3915a9285ae5SZack Kirsch out:
3916a9285ae5SZack Kirsch NFSEXITCODE(error);
39179ec7b004SRick Macklem return (error);
39189ec7b004SRick Macklem }
39199ec7b004SRick Macklem
39209ec7b004SRick Macklem /*
39219ec7b004SRick Macklem * This function is called from the nfssvc(2) system call, to update the
39229ec7b004SRick Macklem * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
39239ec7b004SRick Macklem */
3924b9cc3262SRyan Moeller int
nfssvc_idname(struct nfsd_idargs * nidp)39259ec7b004SRick Macklem nfssvc_idname(struct nfsd_idargs *nidp)
39269ec7b004SRick Macklem {
39279ec7b004SRick Macklem struct nfsusrgrp *nusrp, *usrp, *newusrp;
392884be7e09SRick Macklem struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
392984be7e09SRick Macklem int i, group_locked, groupname_locked, user_locked, username_locked;
39309ec7b004SRick Macklem int error = 0;
39319ec7b004SRick Macklem u_char *cp;
393284be7e09SRick Macklem gid_t *grps;
393384be7e09SRick Macklem struct ucred *cr;
393484be7e09SRick Macklem static int onethread = 0;
393584be7e09SRick Macklem static time_t lasttime = 0;
39369ec7b004SRick Macklem
39378edac6eeSEd Maste if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
39388edac6eeSEd Maste error = EINVAL;
39398edac6eeSEd Maste goto out;
39408edac6eeSEd Maste }
39419ec7b004SRick Macklem if (nidp->nid_flag & NFSID_INITIALIZE) {
394284be7e09SRick Macklem cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3943e4a458bbSRick Macklem error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
394484be7e09SRick Macklem if (error != 0) {
394584be7e09SRick Macklem free(cp, M_NFSSTRING);
394684be7e09SRick Macklem goto out;
39479ec7b004SRick Macklem }
3948f0db2b60SRick Macklem if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) ==
3949f0db2b60SRick Macklem 0) {
395084be7e09SRick Macklem /*
395184be7e09SRick Macklem * Free up all the old stuff and reinitialize hash
395284be7e09SRick Macklem * lists. All mutexes for both lists must be locked,
395384be7e09SRick Macklem * with the user/group name ones before the uid/gid
395484be7e09SRick Macklem * ones, to avoid a LOR.
395584be7e09SRick Macklem */
395684be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3957f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
395884be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3959f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
396084be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
396184be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp,
3962f0db2b60SRick Macklem &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp)
396384be7e09SRick Macklem nfsrv_removeuser(usrp, 1);
396484be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3965f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
396684be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3967f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
396884be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3969f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
397084be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3971f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
397284be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
397384be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp,
3974f0db2b60SRick Macklem &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
397584be7e09SRick Macklem nusrp)
397684be7e09SRick Macklem nfsrv_removeuser(usrp, 0);
397784be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3978f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
397984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3980f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
3981f0db2b60SRick Macklem free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
3982f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsname) = NULL;
39839ec7b004SRick Macklem }
3984f0db2b60SRick Macklem if (NFSD_VNET(nfsuserhash) == NULL) {
398584be7e09SRick Macklem /* Allocate the hash tables. */
3986f0db2b60SRick Macklem NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) *
398784be7e09SRick Macklem nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
398884be7e09SRick Macklem M_ZERO);
398984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3990f0db2b60SRick Macklem mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash",
399184be7e09SRick Macklem NULL, MTX_DEF | MTX_DUPOK);
3992f0db2b60SRick Macklem NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) *
399384be7e09SRick Macklem nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
399484be7e09SRick Macklem M_ZERO);
399584be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
3996f0db2b60SRick Macklem mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx,
399784be7e09SRick Macklem "nfsusrhash", NULL, MTX_DEF |
399884be7e09SRick Macklem MTX_DUPOK);
3999f0db2b60SRick Macklem NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) *
400084be7e09SRick Macklem nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
400184be7e09SRick Macklem M_ZERO);
400284be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4003f0db2b60SRick Macklem mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash",
400484be7e09SRick Macklem NULL, MTX_DEF | MTX_DUPOK);
4005f0db2b60SRick Macklem NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) *
400684be7e09SRick Macklem nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
400784be7e09SRick Macklem M_ZERO);
400884be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4009f0db2b60SRick Macklem mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx,
401084be7e09SRick Macklem "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
401184be7e09SRick Macklem }
401284be7e09SRick Macklem /* (Re)initialize the list heads. */
401384be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4014f0db2b60SRick Macklem TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead);
401584be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4016f0db2b60SRick Macklem TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead);
401784be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4018f0db2b60SRick Macklem TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead);
401984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4020f0db2b60SRick Macklem TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead);
40219ec7b004SRick Macklem
40229ec7b004SRick Macklem /*
40239ec7b004SRick Macklem * Put name in "DNS" string.
40249ec7b004SRick Macklem */
4025f0db2b60SRick Macklem NFSD_VNET(nfsrv_dnsname) = cp;
4026f0db2b60SRick Macklem NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid;
4027f0db2b60SRick Macklem NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid;
4028f0db2b60SRick Macklem NFSD_VNET(nfsrv_usercnt) = 0;
4029f0db2b60SRick Macklem NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax;
4030f0db2b60SRick Macklem atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen),
4031f0db2b60SRick Macklem nidp->nid_namelen);
4032a9285ae5SZack Kirsch goto out;
40339ec7b004SRick Macklem }
40349ec7b004SRick Macklem
40359ec7b004SRick Macklem /*
40369ec7b004SRick Macklem * malloc the new one now, so any potential sleep occurs before
40379ec7b004SRick Macklem * manipulation of the lists.
40389ec7b004SRick Macklem */
403984be7e09SRick Macklem newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
404084be7e09SRick Macklem M_NFSUSERGROUP, M_WAITOK | M_ZERO);
4041e4a458bbSRick Macklem error = copyin(nidp->nid_name, newusrp->lug_name,
40429ec7b004SRick Macklem nidp->nid_namelen);
404384be7e09SRick Macklem if (error == 0 && nidp->nid_ngroup > 0 &&
404484be7e09SRick Macklem (nidp->nid_flag & NFSID_ADDUID) != 0) {
404584be7e09SRick Macklem grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
404684be7e09SRick Macklem M_WAITOK);
4047e4a458bbSRick Macklem error = copyin(nidp->nid_grps, grps,
404884be7e09SRick Macklem sizeof(gid_t) * nidp->nid_ngroup);
404984be7e09SRick Macklem if (error == 0) {
405084be7e09SRick Macklem /*
405184be7e09SRick Macklem * Create a credential just like svc_getcred(),
405284be7e09SRick Macklem * but using the group list provided.
405384be7e09SRick Macklem */
405484be7e09SRick Macklem cr = crget();
405584be7e09SRick Macklem cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
4056cfbe7a62SOlivier Certner crsetgroups_fallback(cr, nidp->nid_ngroup, grps,
40575169d430SOlivier Certner GID_NOGROUP);
4058cfbe7a62SOlivier Certner cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
4059f0db2b60SRick Macklem cr->cr_prison = curthread->td_ucred->cr_prison;
406084be7e09SRick Macklem prison_hold(cr->cr_prison);
406184be7e09SRick Macklem #ifdef MAC
406284be7e09SRick Macklem mac_cred_associate_nfsd(cr);
406384be7e09SRick Macklem #endif
406484be7e09SRick Macklem newusrp->lug_cred = cr;
406584be7e09SRick Macklem }
406684be7e09SRick Macklem free(grps, M_TEMP);
406784be7e09SRick Macklem }
40689ec7b004SRick Macklem if (error) {
406984be7e09SRick Macklem free(newusrp, M_NFSUSERGROUP);
4070a9285ae5SZack Kirsch goto out;
40719ec7b004SRick Macklem }
40729ec7b004SRick Macklem newusrp->lug_namelen = nidp->nid_namelen;
40739ec7b004SRick Macklem
407484be7e09SRick Macklem /*
407584be7e09SRick Macklem * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
407684be7e09SRick Macklem * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
407784be7e09SRick Macklem * The flags user_locked, username_locked, group_locked and
407884be7e09SRick Macklem * groupname_locked are set to indicate all of those hash lists are
407984be7e09SRick Macklem * locked. hp_name != NULL and hp_idnum != NULL indicates that
408084be7e09SRick Macklem * the respective one mutex is locked.
408184be7e09SRick Macklem */
408284be7e09SRick Macklem user_locked = username_locked = group_locked = groupname_locked = 0;
408384be7e09SRick Macklem hp_name = hp_idnum = NULL;
408484be7e09SRick Macklem
40859ec7b004SRick Macklem /*
40869ec7b004SRick Macklem * Delete old entries, as required.
40879ec7b004SRick Macklem */
40889ec7b004SRick Macklem if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
408984be7e09SRick Macklem /* Must lock all username hash lists first, to avoid a LOR. */
409084be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4091f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
409284be7e09SRick Macklem username_locked = 1;
409384be7e09SRick Macklem hp_idnum = NFSUSERHASH(nidp->nid_uid);
409484be7e09SRick Macklem mtx_lock(&hp_idnum->mtx);
409584be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
409684be7e09SRick Macklem nusrp) {
40979ec7b004SRick Macklem if (usrp->lug_uid == nidp->nid_uid)
409884be7e09SRick Macklem nfsrv_removeuser(usrp, 1);
40999ec7b004SRick Macklem }
410084be7e09SRick Macklem } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
410184be7e09SRick Macklem hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
410284be7e09SRick Macklem newusrp->lug_namelen);
410384be7e09SRick Macklem mtx_lock(&hp_name->mtx);
410484be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
410584be7e09SRick Macklem nusrp) {
41069ec7b004SRick Macklem if (usrp->lug_namelen == newusrp->lug_namelen &&
41079ec7b004SRick Macklem !NFSBCMP(usrp->lug_name, newusrp->lug_name,
410884be7e09SRick Macklem usrp->lug_namelen)) {
410984be7e09SRick Macklem thp = NFSUSERHASH(usrp->lug_uid);
411084be7e09SRick Macklem mtx_lock(&thp->mtx);
411184be7e09SRick Macklem nfsrv_removeuser(usrp, 1);
411284be7e09SRick Macklem mtx_unlock(&thp->mtx);
41139ec7b004SRick Macklem }
41149ec7b004SRick Macklem }
411584be7e09SRick Macklem hp_idnum = NFSUSERHASH(nidp->nid_uid);
411684be7e09SRick Macklem mtx_lock(&hp_idnum->mtx);
411784be7e09SRick Macklem } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
411884be7e09SRick Macklem /* Must lock all groupname hash lists first, to avoid a LOR. */
411984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4120f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
412184be7e09SRick Macklem groupname_locked = 1;
412284be7e09SRick Macklem hp_idnum = NFSGROUPHASH(nidp->nid_gid);
412384be7e09SRick Macklem mtx_lock(&hp_idnum->mtx);
412484be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
412584be7e09SRick Macklem nusrp) {
41269ec7b004SRick Macklem if (usrp->lug_gid == nidp->nid_gid)
412784be7e09SRick Macklem nfsrv_removeuser(usrp, 0);
41289ec7b004SRick Macklem }
412984be7e09SRick Macklem } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
413084be7e09SRick Macklem hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
413184be7e09SRick Macklem newusrp->lug_namelen);
413284be7e09SRick Macklem mtx_lock(&hp_name->mtx);
413384be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
413484be7e09SRick Macklem nusrp) {
41359ec7b004SRick Macklem if (usrp->lug_namelen == newusrp->lug_namelen &&
41369ec7b004SRick Macklem !NFSBCMP(usrp->lug_name, newusrp->lug_name,
413784be7e09SRick Macklem usrp->lug_namelen)) {
413884be7e09SRick Macklem thp = NFSGROUPHASH(usrp->lug_gid);
413984be7e09SRick Macklem mtx_lock(&thp->mtx);
414084be7e09SRick Macklem nfsrv_removeuser(usrp, 0);
414184be7e09SRick Macklem mtx_unlock(&thp->mtx);
41429ec7b004SRick Macklem }
41439ec7b004SRick Macklem }
414484be7e09SRick Macklem hp_idnum = NFSGROUPHASH(nidp->nid_gid);
414584be7e09SRick Macklem mtx_lock(&hp_idnum->mtx);
41469ec7b004SRick Macklem }
41479ec7b004SRick Macklem
41489ec7b004SRick Macklem /*
41499ec7b004SRick Macklem * Now, we can add the new one.
41509ec7b004SRick Macklem */
41519ec7b004SRick Macklem if (nidp->nid_usertimeout)
41529ec7b004SRick Macklem newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
41539ec7b004SRick Macklem else
41549ec7b004SRick Macklem newusrp->lug_expiry = NFSD_MONOSEC + 5;
41559ec7b004SRick Macklem if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
41569ec7b004SRick Macklem newusrp->lug_uid = nidp->nid_uid;
415784be7e09SRick Macklem thp = NFSUSERHASH(newusrp->lug_uid);
415884be7e09SRick Macklem mtx_assert(&thp->mtx, MA_OWNED);
415984be7e09SRick Macklem TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
416084be7e09SRick Macklem thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
416184be7e09SRick Macklem mtx_assert(&thp->mtx, MA_OWNED);
416284be7e09SRick Macklem TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4163f0db2b60SRick Macklem atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
41649ec7b004SRick Macklem } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
41659ec7b004SRick Macklem newusrp->lug_gid = nidp->nid_gid;
416684be7e09SRick Macklem thp = NFSGROUPHASH(newusrp->lug_gid);
416784be7e09SRick Macklem mtx_assert(&thp->mtx, MA_OWNED);
416884be7e09SRick Macklem TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
416984be7e09SRick Macklem thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
417084be7e09SRick Macklem mtx_assert(&thp->mtx, MA_OWNED);
417184be7e09SRick Macklem TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4172f0db2b60SRick Macklem atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
417384be7e09SRick Macklem } else {
417484be7e09SRick Macklem if (newusrp->lug_cred != NULL)
417584be7e09SRick Macklem crfree(newusrp->lug_cred);
417684be7e09SRick Macklem free(newusrp, M_NFSUSERGROUP);
417784be7e09SRick Macklem }
417884be7e09SRick Macklem
417984be7e09SRick Macklem /*
418084be7e09SRick Macklem * Once per second, allow one thread to trim the cache.
418184be7e09SRick Macklem */
418284be7e09SRick Macklem if (lasttime < NFSD_MONOSEC &&
418384be7e09SRick Macklem atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
418484be7e09SRick Macklem /*
418584be7e09SRick Macklem * First, unlock the single mutexes, so that all entries
418684be7e09SRick Macklem * can be locked and any LOR is avoided.
418784be7e09SRick Macklem */
418884be7e09SRick Macklem if (hp_name != NULL) {
418984be7e09SRick Macklem mtx_unlock(&hp_name->mtx);
419084be7e09SRick Macklem hp_name = NULL;
419184be7e09SRick Macklem }
419284be7e09SRick Macklem if (hp_idnum != NULL) {
419384be7e09SRick Macklem mtx_unlock(&hp_idnum->mtx);
419484be7e09SRick Macklem hp_idnum = NULL;
419584be7e09SRick Macklem }
419684be7e09SRick Macklem
419784be7e09SRick Macklem if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
419884be7e09SRick Macklem NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
419984be7e09SRick Macklem if (username_locked == 0) {
420084be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4201f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
420284be7e09SRick Macklem username_locked = 1;
420384be7e09SRick Macklem }
420484be7e09SRick Macklem KASSERT(user_locked == 0,
420584be7e09SRick Macklem ("nfssvc_idname: user_locked"));
420684be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4207f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
420884be7e09SRick Macklem user_locked = 1;
420984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++) {
421084be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp,
4211f0db2b60SRick Macklem &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
421284be7e09SRick Macklem nusrp)
421384be7e09SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
421484be7e09SRick Macklem nfsrv_removeuser(usrp, 1);
421584be7e09SRick Macklem }
421684be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++) {
421784be7e09SRick Macklem /*
421884be7e09SRick Macklem * Trim the cache using an approximate LRU
421984be7e09SRick Macklem * algorithm. This code deletes the least
422084be7e09SRick Macklem * recently used entry on each hash list.
422184be7e09SRick Macklem */
4222f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
422384be7e09SRick Macklem break;
4224f0db2b60SRick Macklem usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead);
422584be7e09SRick Macklem if (usrp != NULL)
422684be7e09SRick Macklem nfsrv_removeuser(usrp, 1);
422784be7e09SRick Macklem }
422884be7e09SRick Macklem } else {
422984be7e09SRick Macklem if (groupname_locked == 0) {
423084be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4231f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
423284be7e09SRick Macklem groupname_locked = 1;
423384be7e09SRick Macklem }
423484be7e09SRick Macklem KASSERT(group_locked == 0,
423584be7e09SRick Macklem ("nfssvc_idname: group_locked"));
423684be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4237f0db2b60SRick Macklem mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
423884be7e09SRick Macklem group_locked = 1;
423984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++) {
424084be7e09SRick Macklem TAILQ_FOREACH_SAFE(usrp,
4241f0db2b60SRick Macklem &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
424284be7e09SRick Macklem nusrp)
424384be7e09SRick Macklem if (usrp->lug_expiry < NFSD_MONOSEC)
424484be7e09SRick Macklem nfsrv_removeuser(usrp, 0);
424584be7e09SRick Macklem }
424684be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++) {
424784be7e09SRick Macklem /*
424884be7e09SRick Macklem * Trim the cache using an approximate LRU
424984be7e09SRick Macklem * algorithm. This code deletes the least
425084be7e09SRick Macklem * recently user entry on each hash list.
425184be7e09SRick Macklem */
4252f0db2b60SRick Macklem if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
425384be7e09SRick Macklem break;
4254f0db2b60SRick Macklem usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead);
425584be7e09SRick Macklem if (usrp != NULL)
425684be7e09SRick Macklem nfsrv_removeuser(usrp, 0);
425784be7e09SRick Macklem }
425884be7e09SRick Macklem }
425984be7e09SRick Macklem lasttime = NFSD_MONOSEC;
426084be7e09SRick Macklem atomic_store_rel_int(&onethread, 0);
426184be7e09SRick Macklem }
426284be7e09SRick Macklem
426384be7e09SRick Macklem /* Now, unlock all locked mutexes. */
426484be7e09SRick Macklem if (hp_idnum != NULL)
426584be7e09SRick Macklem mtx_unlock(&hp_idnum->mtx);
426684be7e09SRick Macklem if (hp_name != NULL)
426784be7e09SRick Macklem mtx_unlock(&hp_name->mtx);
426884be7e09SRick Macklem if (user_locked != 0)
426984be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4270f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
427184be7e09SRick Macklem if (username_locked != 0)
427284be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4273f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
427484be7e09SRick Macklem if (group_locked != 0)
427584be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4276f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
427784be7e09SRick Macklem if (groupname_locked != 0)
427884be7e09SRick Macklem for (i = 0; i < nfsrv_lughashsize; i++)
4279f0db2b60SRick Macklem mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4280a9285ae5SZack Kirsch out:
4281a9285ae5SZack Kirsch NFSEXITCODE(error);
42829ec7b004SRick Macklem return (error);
42839ec7b004SRick Macklem }
42849ec7b004SRick Macklem
42859ec7b004SRick Macklem /*
42869ec7b004SRick Macklem * Remove a user/group name element.
42879ec7b004SRick Macklem */
42889ec7b004SRick Macklem static void
nfsrv_removeuser(struct nfsusrgrp * usrp,int isuser)428984be7e09SRick Macklem nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
42909ec7b004SRick Macklem {
429184be7e09SRick Macklem struct nfsrv_lughash *hp;
42929ec7b004SRick Macklem
429384be7e09SRick Macklem if (isuser != 0) {
429484be7e09SRick Macklem hp = NFSUSERHASH(usrp->lug_uid);
429584be7e09SRick Macklem mtx_assert(&hp->mtx, MA_OWNED);
429684be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
429784be7e09SRick Macklem hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
429884be7e09SRick Macklem mtx_assert(&hp->mtx, MA_OWNED);
429984be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
430084be7e09SRick Macklem } else {
430184be7e09SRick Macklem hp = NFSGROUPHASH(usrp->lug_gid);
430284be7e09SRick Macklem mtx_assert(&hp->mtx, MA_OWNED);
430384be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
430484be7e09SRick Macklem hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
430584be7e09SRick Macklem mtx_assert(&hp->mtx, MA_OWNED);
430684be7e09SRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
430784be7e09SRick Macklem }
4308f0db2b60SRick Macklem atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1);
430984be7e09SRick Macklem if (usrp->lug_cred != NULL)
431084be7e09SRick Macklem crfree(usrp->lug_cred);
431184be7e09SRick Macklem free(usrp, M_NFSUSERGROUP);
43129ec7b004SRick Macklem }
43139ec7b004SRick Macklem
43149ec7b004SRick Macklem /*
431565171ebbSRick Macklem * Free up all the allocations related to the name<-->id cache.
431665171ebbSRick Macklem * This function should only be called when the nfsuserd daemon isn't
431765171ebbSRick Macklem * running, since it doesn't do any locking.
4318f0db2b60SRick Macklem * This function is meant to be called when a vnet jail is destroyed.
431965171ebbSRick Macklem */
4320b9cc3262SRyan Moeller void
nfsrv_cleanusergroup(void)432165171ebbSRick Macklem nfsrv_cleanusergroup(void)
432265171ebbSRick Macklem {
432365171ebbSRick Macklem struct nfsrv_lughash *hp, *hp2;
432465171ebbSRick Macklem struct nfsusrgrp *nusrp, *usrp;
432565171ebbSRick Macklem int i;
432665171ebbSRick Macklem
4327f0db2b60SRick Macklem if (NFSD_VNET(nfsuserhash) == NULL)
432865171ebbSRick Macklem return;
432965171ebbSRick Macklem
433065171ebbSRick Macklem for (i = 0; i < nfsrv_lughashsize; i++) {
4331f0db2b60SRick Macklem hp = &NFSD_VNET(nfsuserhash)[i];
433265171ebbSRick Macklem TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
433365171ebbSRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
433465171ebbSRick Macklem hp2 = NFSUSERNAMEHASH(usrp->lug_name,
433565171ebbSRick Macklem usrp->lug_namelen);
433665171ebbSRick Macklem TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
433765171ebbSRick Macklem if (usrp->lug_cred != NULL)
433865171ebbSRick Macklem crfree(usrp->lug_cred);
433965171ebbSRick Macklem free(usrp, M_NFSUSERGROUP);
434065171ebbSRick Macklem }
4341f0db2b60SRick Macklem hp = &NFSD_VNET(nfsgrouphash)[i];
434265171ebbSRick Macklem TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
434365171ebbSRick Macklem TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
434465171ebbSRick Macklem hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
434565171ebbSRick Macklem usrp->lug_namelen);
434665171ebbSRick Macklem TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
434765171ebbSRick Macklem if (usrp->lug_cred != NULL)
434865171ebbSRick Macklem crfree(usrp->lug_cred);
434965171ebbSRick Macklem free(usrp, M_NFSUSERGROUP);
435065171ebbSRick Macklem }
4351f0db2b60SRick Macklem mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx);
4352f0db2b60SRick Macklem mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx);
4353f0db2b60SRick Macklem mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4354f0db2b60SRick Macklem mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx);
435565171ebbSRick Macklem }
4356f0db2b60SRick Macklem free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP);
4357f0db2b60SRick Macklem free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP);
4358f0db2b60SRick Macklem free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP);
4359f0db2b60SRick Macklem free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP);
4360f0db2b60SRick Macklem free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
436165171ebbSRick Macklem }
436265171ebbSRick Macklem
436365171ebbSRick Macklem /*
43649ec7b004SRick Macklem * This function scans a byte string and checks for UTF-8 compliance.
43659ec7b004SRick Macklem * It returns 0 if it conforms and NFSERR_INVAL if not.
43669ec7b004SRick Macklem */
4367b9cc3262SRyan Moeller int
nfsrv_checkutf8(u_int8_t * cp,int len)43689ec7b004SRick Macklem nfsrv_checkutf8(u_int8_t *cp, int len)
43699ec7b004SRick Macklem {
43709ec7b004SRick Macklem u_int32_t val = 0x0;
43719ec7b004SRick Macklem int cnt = 0, gotd = 0, shift = 0;
43729ec7b004SRick Macklem u_int8_t byte;
43739ec7b004SRick Macklem static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4374a9285ae5SZack Kirsch int error = 0;
43759ec7b004SRick Macklem
43769ec7b004SRick Macklem /*
43779ec7b004SRick Macklem * Here are what the variables are used for:
43789ec7b004SRick Macklem * val - the calculated value of a multibyte char, used to check
43799ec7b004SRick Macklem * that it was coded with the correct range
43809ec7b004SRick Macklem * cnt - the number of 10xxxxxx bytes to follow
43819ec7b004SRick Macklem * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
43829ec7b004SRick Macklem * shift - lower order bits of range (ie. "val >> shift" should
43839ec7b004SRick Macklem * not be 0, in other words, dividing by the lower bound
43849ec7b004SRick Macklem * of the range should get a non-zero value)
43859ec7b004SRick Macklem * byte - used to calculate cnt
43869ec7b004SRick Macklem */
43879ec7b004SRick Macklem while (len > 0) {
43889ec7b004SRick Macklem if (cnt > 0) {
43899ec7b004SRick Macklem /* This handles the 10xxxxxx bytes */
43909ec7b004SRick Macklem if ((*cp & 0xc0) != 0x80 ||
4391a9285ae5SZack Kirsch (gotd && (*cp & 0x20))) {
4392a9285ae5SZack Kirsch error = NFSERR_INVAL;
4393a9285ae5SZack Kirsch goto out;
4394a9285ae5SZack Kirsch }
43959ec7b004SRick Macklem gotd = 0;
43969ec7b004SRick Macklem val <<= 6;
43979ec7b004SRick Macklem val |= (*cp & 0x3f);
43989ec7b004SRick Macklem cnt--;
4399a9285ae5SZack Kirsch if (cnt == 0 && (val >> shift) == 0x0) {
4400a9285ae5SZack Kirsch error = NFSERR_INVAL;
4401a9285ae5SZack Kirsch goto out;
4402a9285ae5SZack Kirsch }
44039ec7b004SRick Macklem } else if (*cp & 0x80) {
44049ec7b004SRick Macklem /* first byte of multi byte char */
44059ec7b004SRick Macklem byte = *cp;
44069ec7b004SRick Macklem while ((byte & 0x40) && cnt < 6) {
44079ec7b004SRick Macklem cnt++;
44089ec7b004SRick Macklem byte <<= 1;
44099ec7b004SRick Macklem }
4410a9285ae5SZack Kirsch if (cnt == 0 || cnt == 6) {
4411a9285ae5SZack Kirsch error = NFSERR_INVAL;
4412a9285ae5SZack Kirsch goto out;
4413a9285ae5SZack Kirsch }
44149ec7b004SRick Macklem val = (*cp & (0x3f >> cnt));
44159ec7b004SRick Macklem shift = utf8_shift[cnt - 1];
44169ec7b004SRick Macklem if (cnt == 2 && val == 0xd)
44179ec7b004SRick Macklem /* Check for the 0xd800-0xdfff case */
44189ec7b004SRick Macklem gotd = 1;
44199ec7b004SRick Macklem }
44209ec7b004SRick Macklem cp++;
44219ec7b004SRick Macklem len--;
44229ec7b004SRick Macklem }
44239ec7b004SRick Macklem if (cnt > 0)
4424a9285ae5SZack Kirsch error = NFSERR_INVAL;
4425a9285ae5SZack Kirsch
4426a9285ae5SZack Kirsch out:
4427a9285ae5SZack Kirsch NFSEXITCODE(error);
4428a9285ae5SZack Kirsch return (error);
44299ec7b004SRick Macklem }
44309ec7b004SRick Macklem
44319ec7b004SRick Macklem /*
44329ec7b004SRick Macklem * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
44339ec7b004SRick Macklem * strings, one with the root path in it and the other with the list of
44349ec7b004SRick Macklem * locations. The list is in the same format as is found in nfr_refs.
44359ec7b004SRick Macklem * It is a "," separated list of entries, where each of them is of the
44369ec7b004SRick Macklem * form <server>:<rootpath>. For example
44379ec7b004SRick Macklem * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
44389ec7b004SRick Macklem * The nilp argument is set to 1 for the special case of a null fs_root
44399ec7b004SRick Macklem * and an empty server list.
44409ec7b004SRick Macklem * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
44419ec7b004SRick Macklem * number of xdr bytes parsed in sump.
44429ec7b004SRick Macklem */
44439ec7b004SRick Macklem static int
nfsrv_getrefstr(struct nfsrv_descript * nd,u_char ** fsrootp,u_char ** srvp,int * sump,int * nilp)44449ec7b004SRick Macklem nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
44459ec7b004SRick Macklem int *sump, int *nilp)
44469ec7b004SRick Macklem {
44479ec7b004SRick Macklem u_int32_t *tl;
44489ec7b004SRick Macklem u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4449a9285ae5SZack Kirsch int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
44509ec7b004SRick Macklem struct list {
44519ec7b004SRick Macklem SLIST_ENTRY(list) next;
44529ec7b004SRick Macklem int len;
44539ec7b004SRick Macklem u_char host[1];
44549ec7b004SRick Macklem } *lsp, *nlsp;
44559ec7b004SRick Macklem SLIST_HEAD(, list) head;
44569ec7b004SRick Macklem
44579ec7b004SRick Macklem *fsrootp = NULL;
44589ec7b004SRick Macklem *srvp = NULL;
44599ec7b004SRick Macklem *nilp = 0;
44609ec7b004SRick Macklem
44619ec7b004SRick Macklem /*
44629ec7b004SRick Macklem * Get the fs_root path and check for the special case of null path
44639ec7b004SRick Macklem * and 0 length server list.
44649ec7b004SRick Macklem */
44659ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
44669ec7b004SRick Macklem len = fxdr_unsigned(int, *tl);
4467a9285ae5SZack Kirsch if (len < 0 || len > 10240) {
4468a9285ae5SZack Kirsch error = NFSERR_BADXDR;
4469a9285ae5SZack Kirsch goto nfsmout;
4470a9285ae5SZack Kirsch }
44719ec7b004SRick Macklem if (len == 0) {
44729ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4473a9285ae5SZack Kirsch if (*tl != 0) {
4474a9285ae5SZack Kirsch error = NFSERR_BADXDR;
4475a9285ae5SZack Kirsch goto nfsmout;
4476a9285ae5SZack Kirsch }
44779ec7b004SRick Macklem *nilp = 1;
44789ec7b004SRick Macklem *sump = 2 * NFSX_UNSIGNED;
4479a9285ae5SZack Kirsch error = 0;
4480a9285ae5SZack Kirsch goto nfsmout;
44819ec7b004SRick Macklem }
44829ec7b004SRick Macklem cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
44839ec7b004SRick Macklem error = nfsrv_mtostr(nd, cp, len);
44849ec7b004SRick Macklem if (!error) {
44859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
44869ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl);
44879ec7b004SRick Macklem if (cnt <= 0)
44889ec7b004SRick Macklem error = NFSERR_BADXDR;
44899ec7b004SRick Macklem }
4490a9285ae5SZack Kirsch if (error)
4491a9285ae5SZack Kirsch goto nfsmout;
44929ec7b004SRick Macklem
44939ec7b004SRick Macklem /*
44949ec7b004SRick Macklem * Now, loop through the location list and make up the srvlist.
44959ec7b004SRick Macklem */
44969ec7b004SRick Macklem xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
44979ec7b004SRick Macklem cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
44989ec7b004SRick Macklem slen = 1024;
44999ec7b004SRick Macklem siz = 0;
45009ec7b004SRick Macklem for (i = 0; i < cnt; i++) {
45019ec7b004SRick Macklem SLIST_INIT(&head);
45029ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
45039ec7b004SRick Macklem nsrv = fxdr_unsigned(int, *tl);
45049ec7b004SRick Macklem if (nsrv <= 0) {
4505a9285ae5SZack Kirsch error = NFSERR_BADXDR;
4506a9285ae5SZack Kirsch goto nfsmout;
45079ec7b004SRick Macklem }
45089ec7b004SRick Macklem
45099ec7b004SRick Macklem /*
45109ec7b004SRick Macklem * Handle the first server by putting it in the srvstr.
45119ec7b004SRick Macklem */
45129ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
45139ec7b004SRick Macklem len = fxdr_unsigned(int, *tl);
45149ec7b004SRick Macklem if (len <= 0 || len > 1024) {
4515a9285ae5SZack Kirsch error = NFSERR_BADXDR;
4516a9285ae5SZack Kirsch goto nfsmout;
45179ec7b004SRick Macklem }
45189ec7b004SRick Macklem nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
45199ec7b004SRick Macklem if (cp3 != cp2) {
45209ec7b004SRick Macklem *cp3++ = ',';
45219ec7b004SRick Macklem siz++;
45229ec7b004SRick Macklem }
45239ec7b004SRick Macklem error = nfsrv_mtostr(nd, cp3, len);
4524a9285ae5SZack Kirsch if (error)
4525a9285ae5SZack Kirsch goto nfsmout;
45269ec7b004SRick Macklem cp3 += len;
45279ec7b004SRick Macklem *cp3++ = ':';
45289ec7b004SRick Macklem siz += (len + 1);
45299ec7b004SRick Macklem xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
45309ec7b004SRick Macklem for (j = 1; j < nsrv; j++) {
45319ec7b004SRick Macklem /*
45329ec7b004SRick Macklem * Yuck, put them in an slist and process them later.
45339ec7b004SRick Macklem */
45349ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
45359ec7b004SRick Macklem len = fxdr_unsigned(int, *tl);
45369ec7b004SRick Macklem if (len <= 0 || len > 1024) {
4537a9285ae5SZack Kirsch error = NFSERR_BADXDR;
4538a9285ae5SZack Kirsch goto nfsmout;
45399ec7b004SRick Macklem }
45409ec7b004SRick Macklem lsp = (struct list *)malloc(sizeof (struct list)
45419ec7b004SRick Macklem + len, M_TEMP, M_WAITOK);
45429ec7b004SRick Macklem error = nfsrv_mtostr(nd, lsp->host, len);
4543a9285ae5SZack Kirsch if (error)
4544a9285ae5SZack Kirsch goto nfsmout;
45459ec7b004SRick Macklem xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
45469ec7b004SRick Macklem lsp->len = len;
45479ec7b004SRick Macklem SLIST_INSERT_HEAD(&head, lsp, next);
45489ec7b004SRick Macklem }
45499ec7b004SRick Macklem
45509ec7b004SRick Macklem /*
45519ec7b004SRick Macklem * Finally, we can get the path.
45529ec7b004SRick Macklem */
45539ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
45549ec7b004SRick Macklem len = fxdr_unsigned(int, *tl);
45559ec7b004SRick Macklem if (len <= 0 || len > 1024) {
4556a9285ae5SZack Kirsch error = NFSERR_BADXDR;
4557a9285ae5SZack Kirsch goto nfsmout;
45589ec7b004SRick Macklem }
45599ec7b004SRick Macklem nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
45609ec7b004SRick Macklem error = nfsrv_mtostr(nd, cp3, len);
4561a9285ae5SZack Kirsch if (error)
4562a9285ae5SZack Kirsch goto nfsmout;
45639ec7b004SRick Macklem xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
45649ec7b004SRick Macklem str = cp3;
45659ec7b004SRick Macklem stringlen = len;
45669ec7b004SRick Macklem cp3 += len;
45679ec7b004SRick Macklem siz += len;
45689ec7b004SRick Macklem SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
45699ec7b004SRick Macklem nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
45709ec7b004SRick Macklem &cp2, &cp3, &slen);
45719ec7b004SRick Macklem *cp3++ = ',';
45729ec7b004SRick Macklem NFSBCOPY(lsp->host, cp3, lsp->len);
45739ec7b004SRick Macklem cp3 += lsp->len;
45749ec7b004SRick Macklem *cp3++ = ':';
45759ec7b004SRick Macklem NFSBCOPY(str, cp3, stringlen);
45769ec7b004SRick Macklem cp3 += stringlen;
45779ec7b004SRick Macklem *cp3 = '\0';
45789ec7b004SRick Macklem siz += (lsp->len + stringlen + 2);
4579222daa42SConrad Meyer free(lsp, M_TEMP);
45809ec7b004SRick Macklem }
45819ec7b004SRick Macklem }
45829ec7b004SRick Macklem *fsrootp = cp;
45839ec7b004SRick Macklem *srvp = cp2;
45849ec7b004SRick Macklem *sump = xdrsum;
4585a9285ae5SZack Kirsch NFSEXITCODE2(0, nd);
45869ec7b004SRick Macklem return (0);
45879ec7b004SRick Macklem nfsmout:
45889ec7b004SRick Macklem if (cp != NULL)
45899ec7b004SRick Macklem free(cp, M_NFSSTRING);
45909ec7b004SRick Macklem if (cp2 != NULL)
45919ec7b004SRick Macklem free(cp2, M_NFSSTRING);
4592a9285ae5SZack Kirsch NFSEXITCODE2(error, nd);
45939ec7b004SRick Macklem return (error);
45949ec7b004SRick Macklem }
45959ec7b004SRick Macklem
45969ec7b004SRick Macklem /*
45979ec7b004SRick Macklem * Make the malloc'd space large enough. This is a pain, but the xdr
45989ec7b004SRick Macklem * doesn't set an upper bound on the side, so...
45999ec7b004SRick Macklem */
46009ec7b004SRick Macklem static void
nfsrv_refstrbigenough(int siz,u_char ** cpp,u_char ** cpp2,int * slenp)46019ec7b004SRick Macklem nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
46029ec7b004SRick Macklem {
46039ec7b004SRick Macklem u_char *cp;
46049ec7b004SRick Macklem int i;
46059ec7b004SRick Macklem
46069ec7b004SRick Macklem if (siz <= *slenp)
46079ec7b004SRick Macklem return;
46089ec7b004SRick Macklem cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
46099ec7b004SRick Macklem NFSBCOPY(*cpp, cp, *slenp);
46109ec7b004SRick Macklem free(*cpp, M_NFSSTRING);
46119ec7b004SRick Macklem i = *cpp2 - *cpp;
46129ec7b004SRick Macklem *cpp = cp;
46139ec7b004SRick Macklem *cpp2 = cp + i;
46149ec7b004SRick Macklem *slenp = siz + 1024;
46159ec7b004SRick Macklem }
46169ec7b004SRick Macklem
46179ec7b004SRick Macklem /*
46189ec7b004SRick Macklem * Initialize the reply header data structures.
46199ec7b004SRick Macklem */
4620b9cc3262SRyan Moeller void
nfsrvd_rephead(struct nfsrv_descript * nd)46219ec7b004SRick Macklem nfsrvd_rephead(struct nfsrv_descript *nd)
46229ec7b004SRick Macklem {
4623ae070589SRick Macklem struct mbuf *mreq;
46249ec7b004SRick Macklem
4625022346faSRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0) {
4626022346faSRick Macklem mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4627022346faSRick Macklem nd->nd_mreq = nd->nd_mb = mreq;
4628022346faSRick Macklem nd->nd_bpos = (char *)(void *)
4629022346faSRick Macklem PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4630022346faSRick Macklem nd->nd_bextpg = 0;
4631022346faSRick Macklem nd->nd_bextpgsiz = PAGE_SIZE;
4632022346faSRick Macklem } else {
46339ec7b004SRick Macklem /*
46349ec7b004SRick Macklem * If this is a big reply, use a cluster.
46359ec7b004SRick Macklem */
46369ec7b004SRick Macklem if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
46379ec7b004SRick Macklem nfs_bigreply[nd->nd_procnum]) {
4638eb1b1807SGleb Smirnoff NFSMCLGET(mreq, M_WAITOK);
46399ec7b004SRick Macklem nd->nd_mreq = mreq;
46409ec7b004SRick Macklem nd->nd_mb = mreq;
46419ec7b004SRick Macklem } else {
46429ec7b004SRick Macklem NFSMGET(mreq);
46439ec7b004SRick Macklem nd->nd_mreq = mreq;
46449ec7b004SRick Macklem nd->nd_mb = mreq;
46459ec7b004SRick Macklem }
4646022346faSRick Macklem nd->nd_bpos = mtod(mreq, char *);
4647c948a17aSRick Macklem mreq->m_len = 0;
4648022346faSRick Macklem }
46499ec7b004SRick Macklem
46509ec7b004SRick Macklem if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
46519ec7b004SRick Macklem NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
46529ec7b004SRick Macklem }
46539ec7b004SRick Macklem
46549ec7b004SRick Macklem /*
46559ec7b004SRick Macklem * Lock a socket against others.
46569ec7b004SRick Macklem * Currently used to serialize connect/disconnect attempts.
46579ec7b004SRick Macklem */
46589ec7b004SRick Macklem int
newnfs_sndlock(int * flagp)46599ec7b004SRick Macklem newnfs_sndlock(int *flagp)
46609ec7b004SRick Macklem {
46619ec7b004SRick Macklem struct timespec ts;
46629ec7b004SRick Macklem
46639ec7b004SRick Macklem NFSLOCKSOCK();
46649ec7b004SRick Macklem while (*flagp & NFSR_SNDLOCK) {
46659ec7b004SRick Macklem *flagp |= NFSR_WANTSND;
46669ec7b004SRick Macklem ts.tv_sec = 0;
46679ec7b004SRick Macklem ts.tv_nsec = 0;
46689ec7b004SRick Macklem (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
46699ec7b004SRick Macklem PZERO - 1, "nfsndlck", &ts);
46709ec7b004SRick Macklem }
46719ec7b004SRick Macklem *flagp |= NFSR_SNDLOCK;
46729ec7b004SRick Macklem NFSUNLOCKSOCK();
46739ec7b004SRick Macklem return (0);
46749ec7b004SRick Macklem }
46759ec7b004SRick Macklem
46769ec7b004SRick Macklem /*
46779ec7b004SRick Macklem * Unlock the stream socket for others.
46789ec7b004SRick Macklem */
46799ec7b004SRick Macklem void
newnfs_sndunlock(int * flagp)46809ec7b004SRick Macklem newnfs_sndunlock(int *flagp)
46819ec7b004SRick Macklem {
46829ec7b004SRick Macklem
46839ec7b004SRick Macklem NFSLOCKSOCK();
46849ec7b004SRick Macklem if ((*flagp & NFSR_SNDLOCK) == 0)
46859ec7b004SRick Macklem panic("nfs sndunlock");
46869ec7b004SRick Macklem *flagp &= ~NFSR_SNDLOCK;
46879ec7b004SRick Macklem if (*flagp & NFSR_WANTSND) {
46889ec7b004SRick Macklem *flagp &= ~NFSR_WANTSND;
46899ec7b004SRick Macklem wakeup((caddr_t)flagp);
46909ec7b004SRick Macklem }
46919ec7b004SRick Macklem NFSUNLOCKSOCK();
46929ec7b004SRick Macklem }
46939ec7b004SRick Macklem
4694b9cc3262SRyan Moeller int
nfsv4_getipaddr(struct nfsrv_descript * nd,struct sockaddr_in * sin,struct sockaddr_in6 * sin6,sa_family_t * saf,int * isudp)4695be3d32adSRick Macklem nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4696be3d32adSRick Macklem struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
46971f60bfd8SRick Macklem {
46981f60bfd8SRick Macklem struct in_addr saddr;
46991f60bfd8SRick Macklem uint32_t portnum, *tl;
4700be3d32adSRick Macklem int i, j, k;
4701be3d32adSRick Macklem sa_family_t af = AF_UNSPEC;
47021f60bfd8SRick Macklem char addr[64], protocol[5], *cp;
47031f60bfd8SRick Macklem int cantparse = 0, error = 0;
47041f60bfd8SRick Macklem uint16_t portv;
47051f60bfd8SRick Macklem
47061f60bfd8SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
47071f60bfd8SRick Macklem i = fxdr_unsigned(int, *tl);
47081f60bfd8SRick Macklem if (i >= 3 && i <= 4) {
47091f60bfd8SRick Macklem error = nfsrv_mtostr(nd, protocol, i);
47101f60bfd8SRick Macklem if (error)
47111f60bfd8SRick Macklem goto nfsmout;
47121f60bfd8SRick Macklem if (strcmp(protocol, "tcp") == 0) {
47131f60bfd8SRick Macklem af = AF_INET;
47141f60bfd8SRick Macklem *isudp = 0;
47151f60bfd8SRick Macklem } else if (strcmp(protocol, "udp") == 0) {
47161f60bfd8SRick Macklem af = AF_INET;
47171f60bfd8SRick Macklem *isudp = 1;
47181f60bfd8SRick Macklem } else if (strcmp(protocol, "tcp6") == 0) {
47191f60bfd8SRick Macklem af = AF_INET6;
47201f60bfd8SRick Macklem *isudp = 0;
47211f60bfd8SRick Macklem } else if (strcmp(protocol, "udp6") == 0) {
47221f60bfd8SRick Macklem af = AF_INET6;
47231f60bfd8SRick Macklem *isudp = 1;
47241f60bfd8SRick Macklem } else
47251f60bfd8SRick Macklem cantparse = 1;
47261f60bfd8SRick Macklem } else {
47271f60bfd8SRick Macklem cantparse = 1;
47281f60bfd8SRick Macklem if (i > 0) {
47291f60bfd8SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
47301f60bfd8SRick Macklem if (error)
47311f60bfd8SRick Macklem goto nfsmout;
47321f60bfd8SRick Macklem }
47331f60bfd8SRick Macklem }
47341f60bfd8SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
47351f60bfd8SRick Macklem i = fxdr_unsigned(int, *tl);
47361f60bfd8SRick Macklem if (i < 0) {
47371f60bfd8SRick Macklem error = NFSERR_BADXDR;
47381f60bfd8SRick Macklem goto nfsmout;
47391f60bfd8SRick Macklem } else if (cantparse == 0 && i >= 11 && i < 64) {
47401f60bfd8SRick Macklem /*
47411f60bfd8SRick Macklem * The shortest address is 11chars and the longest is < 64.
47421f60bfd8SRick Macklem */
47431f60bfd8SRick Macklem error = nfsrv_mtostr(nd, addr, i);
47441f60bfd8SRick Macklem if (error)
47451f60bfd8SRick Macklem goto nfsmout;
47461f60bfd8SRick Macklem
47471f60bfd8SRick Macklem /* Find the port# at the end and extract that. */
47481f60bfd8SRick Macklem i = strlen(addr);
47491f60bfd8SRick Macklem k = 0;
47501f60bfd8SRick Macklem cp = &addr[i - 1];
47511f60bfd8SRick Macklem /* Count back two '.'s from end to get port# field. */
47521f60bfd8SRick Macklem for (j = 0; j < i; j++) {
47531f60bfd8SRick Macklem if (*cp == '.') {
47541f60bfd8SRick Macklem k++;
47551f60bfd8SRick Macklem if (k == 2)
47561f60bfd8SRick Macklem break;
47571f60bfd8SRick Macklem }
47581f60bfd8SRick Macklem cp--;
47591f60bfd8SRick Macklem }
47601f60bfd8SRick Macklem if (k == 2) {
47611f60bfd8SRick Macklem /*
47621f60bfd8SRick Macklem * The NFSv4 port# is appended as .N.N, where N is
47631f60bfd8SRick Macklem * a decimal # in the range 0-255, just like an inet4
47641f60bfd8SRick Macklem * address. Cheat and use inet_aton(), which will
47651f60bfd8SRick Macklem * return a Class A address and then shift the high
47661f60bfd8SRick Macklem * order 8bits over to convert it to the port#.
47671f60bfd8SRick Macklem */
47681f60bfd8SRick Macklem *cp++ = '\0';
47691f60bfd8SRick Macklem if (inet_aton(cp, &saddr) == 1) {
47701f60bfd8SRick Macklem portnum = ntohl(saddr.s_addr);
47711f60bfd8SRick Macklem portv = (uint16_t)((portnum >> 16) |
47721f60bfd8SRick Macklem (portnum & 0xff));
47731f60bfd8SRick Macklem } else
47741f60bfd8SRick Macklem cantparse = 1;
47751f60bfd8SRick Macklem } else
47761f60bfd8SRick Macklem cantparse = 1;
47771f60bfd8SRick Macklem if (cantparse == 0) {
47781f60bfd8SRick Macklem if (af == AF_INET) {
4779be3d32adSRick Macklem if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4780be3d32adSRick Macklem sin->sin_len = sizeof(*sin);
4781be3d32adSRick Macklem sin->sin_family = AF_INET;
4782be3d32adSRick Macklem sin->sin_port = htons(portv);
4783be3d32adSRick Macklem *saf = af;
47841f60bfd8SRick Macklem return (0);
47851f60bfd8SRick Macklem }
47861f60bfd8SRick Macklem } else {
4787be3d32adSRick Macklem if (inet_pton(af, addr, &sin6->sin6_addr)
47881f60bfd8SRick Macklem == 1) {
4789be3d32adSRick Macklem sin6->sin6_len = sizeof(*sin6);
4790be3d32adSRick Macklem sin6->sin6_family = AF_INET6;
4791be3d32adSRick Macklem sin6->sin6_port = htons(portv);
4792be3d32adSRick Macklem *saf = af;
47931f60bfd8SRick Macklem return (0);
47941f60bfd8SRick Macklem }
47951f60bfd8SRick Macklem }
47961f60bfd8SRick Macklem }
47971f60bfd8SRick Macklem } else {
47981f60bfd8SRick Macklem if (i > 0) {
47991f60bfd8SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
48001f60bfd8SRick Macklem if (error)
48011f60bfd8SRick Macklem goto nfsmout;
48021f60bfd8SRick Macklem }
48031f60bfd8SRick Macklem }
48041f60bfd8SRick Macklem error = EPERM;
48051f60bfd8SRick Macklem nfsmout:
48061f60bfd8SRick Macklem return (error);
48071f60bfd8SRick Macklem }
48081f60bfd8SRick Macklem
48091f60bfd8SRick Macklem /*
48101f60bfd8SRick Macklem * Handle an NFSv4.1 Sequence request for the session.
4811c59e4cc3SRick Macklem * If reply != NULL, use it to return the cached reply, as required.
4812c59e4cc3SRick Macklem * The client gets a cached reply via this call for callbacks, however the
481378ffcb86SRick Macklem * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
48141f60bfd8SRick Macklem */
48151f60bfd8SRick Macklem int
nfsv4_seqsession(uint32_t seqid,uint32_t slotid,uint32_t highslot,struct nfsslot * slots,struct mbuf ** reply,uint16_t maxslot)48161f60bfd8SRick Macklem nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
48171f60bfd8SRick Macklem struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
48181f60bfd8SRick Macklem {
481922cefe3dSRick Macklem struct mbuf *m;
48201f60bfd8SRick Macklem int error;
48211f60bfd8SRick Macklem
48221f60bfd8SRick Macklem error = 0;
4823c59e4cc3SRick Macklem if (reply != NULL)
48241f60bfd8SRick Macklem *reply = NULL;
48251f60bfd8SRick Macklem if (slotid > maxslot)
48261f60bfd8SRick Macklem return (NFSERR_BADSLOT);
48271f60bfd8SRick Macklem if (seqid == slots[slotid].nfssl_seq) {
48281f60bfd8SRick Macklem /* A retry. */
48291f60bfd8SRick Macklem if (slots[slotid].nfssl_inprog != 0)
48301f60bfd8SRick Macklem error = NFSERR_DELAY;
48311f60bfd8SRick Macklem else if (slots[slotid].nfssl_reply != NULL) {
4832c59e4cc3SRick Macklem if (reply != NULL) {
483322cefe3dSRick Macklem m = m_copym(slots[slotid].nfssl_reply, 0,
483422cefe3dSRick Macklem M_COPYALL, M_NOWAIT);
483522cefe3dSRick Macklem if (m != NULL)
483622cefe3dSRick Macklem *reply = m;
483722cefe3dSRick Macklem else {
48381f60bfd8SRick Macklem *reply = slots[slotid].nfssl_reply;
48391f60bfd8SRick Macklem slots[slotid].nfssl_reply = NULL;
4840c59e4cc3SRick Macklem }
484122cefe3dSRick Macklem }
48421f60bfd8SRick Macklem slots[slotid].nfssl_inprog = 1;
4843c59e4cc3SRick Macklem error = NFSERR_REPLYFROMCACHE;
48441f60bfd8SRick Macklem } else
4845c59e4cc3SRick Macklem /* No reply cached, so just do it. */
4846c59e4cc3SRick Macklem slots[slotid].nfssl_inprog = 1;
484734256484SRick Macklem } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4848c59e4cc3SRick Macklem if (slots[slotid].nfssl_reply != NULL)
48491f60bfd8SRick Macklem m_freem(slots[slotid].nfssl_reply);
48501f60bfd8SRick Macklem slots[slotid].nfssl_reply = NULL;
48511f60bfd8SRick Macklem slots[slotid].nfssl_inprog = 1;
485234256484SRick Macklem slots[slotid].nfssl_seq++;
48531f60bfd8SRick Macklem } else
48541f60bfd8SRick Macklem error = NFSERR_SEQMISORDERED;
48551f60bfd8SRick Macklem return (error);
48561f60bfd8SRick Macklem }
48571f60bfd8SRick Macklem
48581f60bfd8SRick Macklem /*
48591f60bfd8SRick Macklem * Cache this reply for the slot.
4860c59e4cc3SRick Macklem * Use the "rep" argument to return the cached reply if repstat is set to
4861c59e4cc3SRick Macklem * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
48621f60bfd8SRick Macklem */
48631f60bfd8SRick Macklem void
nfsv4_seqsess_cacherep(uint32_t slotid,struct nfsslot * slots,int repstat,struct mbuf ** rep)4864c59e4cc3SRick Macklem nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4865c59e4cc3SRick Macklem struct mbuf **rep)
48661f60bfd8SRick Macklem {
486722cefe3dSRick Macklem struct mbuf *m;
48681f60bfd8SRick Macklem
4869c59e4cc3SRick Macklem if (repstat == NFSERR_REPLYFROMCACHE) {
487022cefe3dSRick Macklem if (slots[slotid].nfssl_reply != NULL) {
487122cefe3dSRick Macklem /*
487222cefe3dSRick Macklem * We cannot sleep here, but copy will usually
487322cefe3dSRick Macklem * succeed.
487422cefe3dSRick Macklem */
487522cefe3dSRick Macklem m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
487622cefe3dSRick Macklem M_NOWAIT);
487722cefe3dSRick Macklem if (m != NULL)
487822cefe3dSRick Macklem *rep = m;
487922cefe3dSRick Macklem else {
488022cefe3dSRick Macklem /*
488122cefe3dSRick Macklem * Multiple retries would be extremely rare,
488222cefe3dSRick Macklem * so using the cached reply will likely
488322cefe3dSRick Macklem * be ok.
488422cefe3dSRick Macklem */
4885c59e4cc3SRick Macklem *rep = slots[slotid].nfssl_reply;
4886c59e4cc3SRick Macklem slots[slotid].nfssl_reply = NULL;
488722cefe3dSRick Macklem }
488822cefe3dSRick Macklem } else
488922cefe3dSRick Macklem *rep = NULL;
4890c59e4cc3SRick Macklem } else {
4891c59e4cc3SRick Macklem if (slots[slotid].nfssl_reply != NULL)
4892c59e4cc3SRick Macklem m_freem(slots[slotid].nfssl_reply);
4893c59e4cc3SRick Macklem slots[slotid].nfssl_reply = *rep;
4894c59e4cc3SRick Macklem }
48951f60bfd8SRick Macklem slots[slotid].nfssl_inprog = 0;
48961f60bfd8SRick Macklem }
48971f60bfd8SRick Macklem
48981f60bfd8SRick Macklem /*
48991f60bfd8SRick Macklem * Generate the xdr for an NFSv4.1 Sequence Operation.
49001f60bfd8SRick Macklem */
4901b9cc3262SRyan Moeller void
nfsv4_setsequence(struct nfsmount * nmp,struct nfsrv_descript * nd,struct nfsclsession * sep,int dont_replycache,struct ucred * cred)490242b6336aSRick Macklem nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
490340ada74eSRick Macklem struct nfsclsession *sep, int dont_replycache, struct ucred *cred)
49041f60bfd8SRick Macklem {
49051f60bfd8SRick Macklem uint32_t *tl, slotseq = 0;
4906c59e4cc3SRick Macklem int error, maxslot, slotpos;
49071f60bfd8SRick Macklem uint8_t sessionid[NFSX_V4SESSIONID];
49081f60bfd8SRick Macklem
490940ada74eSRick Macklem if (cred != NULL) {
491040ada74eSRick Macklem error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
491140ada74eSRick Macklem &slotseq, sessionid, false);
491240ada74eSRick Macklem if (error == NFSERR_SEQMISORDERED) {
491340ada74eSRick Macklem /* If all slots are bad, Destroy the session. */
491440ada74eSRick Macklem nfsrpc_destroysession(nmp, sep, cred, curthread);
491540ada74eSRick Macklem }
491640ada74eSRick Macklem } else
491740ada74eSRick Macklem error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
491840ada74eSRick Macklem &slotseq, sessionid, true);
4919c057a378SRick Macklem nd->nd_maxreq = sep->nfsess_maxreq;
4920c057a378SRick Macklem nd->nd_maxresp = sep->nfsess_maxresp;
49211f60bfd8SRick Macklem
49221f60bfd8SRick Macklem /* Build the Sequence arguments. */
49231f60bfd8SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4924b2fc0141SRick Macklem nd->nd_sequence = tl;
49251f60bfd8SRick Macklem bcopy(sessionid, tl, NFSX_V4SESSIONID);
49261f60bfd8SRick Macklem tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
49271f60bfd8SRick Macklem nd->nd_slotseq = tl;
4928b2fc0141SRick Macklem if (error == 0) {
49299f4c522eSRick Macklem nd->nd_flag |= ND_HASSLOTID;
49309f4c522eSRick Macklem nd->nd_slotid = slotpos;
49311f60bfd8SRick Macklem *tl++ = txdr_unsigned(slotseq);
49321f60bfd8SRick Macklem *tl++ = txdr_unsigned(slotpos);
49331f60bfd8SRick Macklem *tl++ = txdr_unsigned(maxslot);
49341f60bfd8SRick Macklem if (dont_replycache == 0)
49351f60bfd8SRick Macklem *tl = newnfs_true;
49361f60bfd8SRick Macklem else
49371f60bfd8SRick Macklem *tl = newnfs_false;
4938b2fc0141SRick Macklem } else {
4939b2fc0141SRick Macklem /*
4940b2fc0141SRick Macklem * There are two errors and the rest of the session can
4941b2fc0141SRick Macklem * just be zeros.
4942b2fc0141SRick Macklem * NFSERR_BADSESSION: This bad session should just generate
4943b2fc0141SRick Macklem * the same error again when the RPC is retried.
4944b2fc0141SRick Macklem * ESTALE: A forced dismount is in progress and will cause the
4945b2fc0141SRick Macklem * RPC to fail later.
4946b2fc0141SRick Macklem */
4947b2fc0141SRick Macklem *tl++ = 0;
4948b2fc0141SRick Macklem *tl++ = 0;
4949b2fc0141SRick Macklem *tl++ = 0;
4950b2fc0141SRick Macklem *tl = 0;
4951b2fc0141SRick Macklem }
49521f60bfd8SRick Macklem nd->nd_flag |= ND_HASSEQUENCE;
49531f60bfd8SRick Macklem }
49541f60bfd8SRick Macklem
495540ada74eSRick Macklem /*
495640ada74eSRick Macklem * If fnd_init is true, ignore the badslots.
495740ada74eSRick Macklem * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
495840ada74eSRick Macklem */
4959c59e4cc3SRick Macklem int
nfsv4_sequencelookup(struct nfsmount * nmp,struct nfsclsession * sep,int * slotposp,int * maxslotp,uint32_t * slotseqp,uint8_t * sessionid,bool fnd_init)4960c59e4cc3SRick Macklem nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
496140ada74eSRick Macklem int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
496240ada74eSRick Macklem bool fnd_init)
4963c59e4cc3SRick Macklem {
4964c59e4cc3SRick Macklem int i, maxslot, slotpos;
4965c59e4cc3SRick Macklem uint64_t bitval;
496640ada74eSRick Macklem bool fnd_ok;
4967c59e4cc3SRick Macklem
4968c59e4cc3SRick Macklem /* Find an unused slot. */
4969c59e4cc3SRick Macklem slotpos = -1;
4970c59e4cc3SRick Macklem maxslot = -1;
4971c59e4cc3SRick Macklem mtx_lock(&sep->nfsess_mtx);
4972c59e4cc3SRick Macklem do {
4973b2fc0141SRick Macklem if (nmp != NULL && sep->nfsess_defunct != 0) {
4974b2fc0141SRick Macklem /* Just return the bad session. */
4975b2fc0141SRick Macklem bcopy(sep->nfsess_sessionid, sessionid,
4976b2fc0141SRick Macklem NFSX_V4SESSIONID);
4977b2fc0141SRick Macklem mtx_unlock(&sep->nfsess_mtx);
4978b2fc0141SRick Macklem return (NFSERR_BADSESSION);
4979b2fc0141SRick Macklem }
498040ada74eSRick Macklem fnd_ok = fnd_init;
4981c59e4cc3SRick Macklem bitval = 1;
4982c59e4cc3SRick Macklem for (i = 0; i < sep->nfsess_foreslots; i++) {
498340ada74eSRick Macklem if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
498440ada74eSRick Macklem fnd_ok = true;
4985c59e4cc3SRick Macklem if ((bitval & sep->nfsess_slots) == 0) {
4986c59e4cc3SRick Macklem slotpos = i;
4987c59e4cc3SRick Macklem sep->nfsess_slots |= bitval;
4988c59e4cc3SRick Macklem sep->nfsess_slotseq[i]++;
4989c59e4cc3SRick Macklem *slotseqp = sep->nfsess_slotseq[i];
4990c59e4cc3SRick Macklem break;
4991c59e4cc3SRick Macklem }
499240ada74eSRick Macklem }
4993c59e4cc3SRick Macklem bitval <<= 1;
4994c59e4cc3SRick Macklem }
4995c59e4cc3SRick Macklem if (slotpos == -1) {
4996c59e4cc3SRick Macklem /*
4997c59e4cc3SRick Macklem * If a forced dismount is in progress, just return.
4998c59e4cc3SRick Macklem * This RPC attempt will fail when it calls
4999c59e4cc3SRick Macklem * newnfs_request().
5000c59e4cc3SRick Macklem */
500116f300faSRick Macklem if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
5002c59e4cc3SRick Macklem mtx_unlock(&sep->nfsess_mtx);
5003c59e4cc3SRick Macklem return (ESTALE);
5004c59e4cc3SRick Macklem }
5005c59e4cc3SRick Macklem /* Wake up once/sec, to check for a forced dismount. */
500640ada74eSRick Macklem if (fnd_ok)
500740ada74eSRick Macklem mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
5008c59e4cc3SRick Macklem PZERO, "nfsclseq", hz);
5009c59e4cc3SRick Macklem }
501040ada74eSRick Macklem } while (slotpos == -1 && fnd_ok);
501140ada74eSRick Macklem /*
501240ada74eSRick Macklem * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
501340ada74eSRick Macklem * The caller will do a DestroySession, so that the session's use
501440ada74eSRick Macklem * will get a NFSERR_BADSESSION reply from the server.
501540ada74eSRick Macklem */
501640ada74eSRick Macklem if (!fnd_ok)
501740ada74eSRick Macklem slotpos = 0;
501840ada74eSRick Macklem
5019c59e4cc3SRick Macklem /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
5020c59e4cc3SRick Macklem bitval = 1;
5021c59e4cc3SRick Macklem for (i = 0; i < 64; i++) {
5022c59e4cc3SRick Macklem if ((bitval & sep->nfsess_slots) != 0)
5023c59e4cc3SRick Macklem maxslot = i;
5024c59e4cc3SRick Macklem bitval <<= 1;
5025c59e4cc3SRick Macklem }
5026c59e4cc3SRick Macklem bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
5027c59e4cc3SRick Macklem mtx_unlock(&sep->nfsess_mtx);
5028c59e4cc3SRick Macklem *slotposp = slotpos;
5029c59e4cc3SRick Macklem *maxslotp = maxslot;
503040ada74eSRick Macklem
503140ada74eSRick Macklem if (!fnd_ok)
503240ada74eSRick Macklem return (NFSERR_SEQMISORDERED);
5033c59e4cc3SRick Macklem return (0);
5034c59e4cc3SRick Macklem }
5035c59e4cc3SRick Macklem
50361f60bfd8SRick Macklem /*
50371f60bfd8SRick Macklem * Free a session slot.
50381f60bfd8SRick Macklem */
5039b9cc3262SRyan Moeller void
nfsv4_freeslot(struct nfsclsession * sep,int slot,bool resetseq)504087597731SRick Macklem nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
50411f60bfd8SRick Macklem {
50421f60bfd8SRick Macklem uint64_t bitval;
50431f60bfd8SRick Macklem
50441f60bfd8SRick Macklem bitval = 1;
50451f60bfd8SRick Macklem if (slot > 0)
50461f60bfd8SRick Macklem bitval <<= slot;
50471f60bfd8SRick Macklem mtx_lock(&sep->nfsess_mtx);
504887597731SRick Macklem if (resetseq)
504987597731SRick Macklem sep->nfsess_slotseq[slot]--;
5050*b97a4788SRick Macklem else if (slot > sep->nfsess_foreslots)
5051*b97a4788SRick Macklem sep->nfsess_slotseq[slot] = 0;
50521f60bfd8SRick Macklem if ((bitval & sep->nfsess_slots) == 0)
50531f60bfd8SRick Macklem printf("freeing free slot!!\n");
50541f60bfd8SRick Macklem sep->nfsess_slots &= ~bitval;
50551f60bfd8SRick Macklem wakeup(&sep->nfsess_slots);
50561f60bfd8SRick Macklem mtx_unlock(&sep->nfsess_mtx);
50571f60bfd8SRick Macklem }
50581f60bfd8SRick Macklem
505990d2dfabSRick Macklem /*
50602f32675cSRick Macklem * Search for a matching pnfsd DS, based on the nmp arg.
506190d2dfabSRick Macklem * Return one if found, NULL otherwise.
506290d2dfabSRick Macklem */
506390d2dfabSRick Macklem struct nfsdevice *
nfsv4_findmirror(struct nfsmount * nmp)506490d2dfabSRick Macklem nfsv4_findmirror(struct nfsmount *nmp)
506590d2dfabSRick Macklem {
50662f32675cSRick Macklem struct nfsdevice *ds;
506790d2dfabSRick Macklem
506890d2dfabSRick Macklem mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
506990d2dfabSRick Macklem /*
507090d2dfabSRick Macklem * Search the DS server list for a match with nmp.
507190d2dfabSRick Macklem */
507290d2dfabSRick Macklem if (nfsrv_devidcnt == 0)
50732f32675cSRick Macklem return (NULL);
507490d2dfabSRick Macklem TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
507590d2dfabSRick Macklem if (ds->nfsdev_nmp == nmp) {
50762f32675cSRick Macklem NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
507790d2dfabSRick Macklem break;
507890d2dfabSRick Macklem }
507990d2dfabSRick Macklem }
50802f32675cSRick Macklem return (ds);
508190d2dfabSRick Macklem }
508290d2dfabSRick Macklem
50833d7650f0SRick Macklem /*
50843d7650f0SRick Macklem * Fill in the fields of "struct nfsrv_descript".
50853d7650f0SRick Macklem */
50863d7650f0SRick Macklem void
nfsm_set(struct nfsrv_descript * nd,u_int offs)50873d7650f0SRick Macklem nfsm_set(struct nfsrv_descript *nd, u_int offs)
50883d7650f0SRick Macklem {
50893d7650f0SRick Macklem struct mbuf *m;
5090dccb5806SRick Macklem int rlen;
50913d7650f0SRick Macklem
50923d7650f0SRick Macklem m = nd->nd_mb;
5093dccb5806SRick Macklem if ((m->m_flags & M_EXTPG) != 0) {
5094dccb5806SRick Macklem nd->nd_bextpg = 0;
5095dccb5806SRick Macklem while (offs > 0) {
5096dccb5806SRick Macklem if (nd->nd_bextpg == 0)
5097dccb5806SRick Macklem rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
5098dccb5806SRick Macklem else
5099dccb5806SRick Macklem rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
5100dccb5806SRick Macklem if (offs <= rlen)
5101dccb5806SRick Macklem break;
5102dccb5806SRick Macklem offs -= rlen;
5103dccb5806SRick Macklem nd->nd_bextpg++;
5104dccb5806SRick Macklem if (nd->nd_bextpg == m->m_epg_npgs) {
5105dccb5806SRick Macklem printf("nfsm_set: build offs "
5106dccb5806SRick Macklem "out of range\n");
5107dccb5806SRick Macklem nd->nd_bextpg--;
5108dccb5806SRick Macklem break;
5109dccb5806SRick Macklem }
5110dccb5806SRick Macklem }
5111dccb5806SRick Macklem nd->nd_bpos = (char *)(void *)
5112dccb5806SRick Macklem PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
5113dccb5806SRick Macklem if (nd->nd_bextpg == 0)
5114dccb5806SRick Macklem nd->nd_bpos += m->m_epg_1st_off;
5115dccb5806SRick Macklem if (offs > 0) {
5116dccb5806SRick Macklem nd->nd_bpos += offs;
5117dccb5806SRick Macklem nd->nd_bextpgsiz = rlen - offs;
5118dccb5806SRick Macklem } else if (nd->nd_bextpg == 0)
5119dccb5806SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
5120dccb5806SRick Macklem else
5121dccb5806SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE;
5122dccb5806SRick Macklem } else
51233d7650f0SRick Macklem nd->nd_bpos = mtod(m, char *) + offs;
51243d7650f0SRick Macklem }
512534fc29e0SRick Macklem
512634fc29e0SRick Macklem /*
512734fc29e0SRick Macklem * Grow a ext_pgs mbuf list. Either allocate another page or add
512834fc29e0SRick Macklem * an mbuf to the list.
512934fc29e0SRick Macklem */
513034fc29e0SRick Macklem struct mbuf *
nfsm_add_ext_pgs(struct mbuf * m,int maxextsiz,int * bextpg)513134fc29e0SRick Macklem nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
513234fc29e0SRick Macklem {
513334fc29e0SRick Macklem struct mbuf *mp;
513434fc29e0SRick Macklem vm_page_t pg;
513534fc29e0SRick Macklem
513634fc29e0SRick Macklem if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
513734fc29e0SRick Macklem mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
513834fc29e0SRick Macklem *bextpg = 0;
513934fc29e0SRick Macklem m->m_next = mp;
514034fc29e0SRick Macklem } else {
5141a4667e09SMark Johnston pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
514234fc29e0SRick Macklem VM_ALLOC_WIRED);
514334fc29e0SRick Macklem m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
514434fc29e0SRick Macklem *bextpg = m->m_epg_npgs;
514534fc29e0SRick Macklem m->m_epg_npgs++;
514634fc29e0SRick Macklem m->m_epg_last_len = 0;
514734fc29e0SRick Macklem mp = m;
514834fc29e0SRick Macklem }
514934fc29e0SRick Macklem return (mp);
515034fc29e0SRick Macklem }
5151dff31ae1SRick Macklem
5152dff31ae1SRick Macklem /*
5153dff31ae1SRick Macklem * Do the NFSv4.1 Destroy Session.
5154dff31ae1SRick Macklem */
5155dff31ae1SRick Macklem int
nfsrpc_destroysession(struct nfsmount * nmp,struct nfsclsession * tsep,struct ucred * cred,NFSPROC_T * p)5156dff31ae1SRick Macklem nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
5157dff31ae1SRick Macklem struct ucred *cred, NFSPROC_T *p)
5158dff31ae1SRick Macklem {
5159dff31ae1SRick Macklem uint32_t *tl;
5160dff31ae1SRick Macklem struct nfsrv_descript nfsd;
5161dff31ae1SRick Macklem struct nfsrv_descript *nd = &nfsd;
5162dff31ae1SRick Macklem int error;
5163dff31ae1SRick Macklem
5164db7257efSRick Macklem if (tsep == NULL)
5165db7257efSRick Macklem tsep = nfsmnt_mdssession(nmp);
5166db7257efSRick Macklem if (tsep == NULL)
5167db7257efSRick Macklem return (0);
5168dff31ae1SRick Macklem nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
5169dff31ae1SRick Macklem 0, NULL);
5170dff31ae1SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
5171dff31ae1SRick Macklem bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
5172dff31ae1SRick Macklem nd->nd_flag |= ND_USEGSSNAME;
5173dff31ae1SRick Macklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5174dff31ae1SRick Macklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5175dff31ae1SRick Macklem if (error != 0)
5176dff31ae1SRick Macklem return (error);
5177dff31ae1SRick Macklem error = nd->nd_repstat;
5178dff31ae1SRick Macklem m_freem(nd->nd_mrep);
5179dff31ae1SRick Macklem return (error);
5180dff31ae1SRick Macklem }
5181