1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 1989, 1993
3191783Srmacklem *	The Regents of the University of California.  All rights reserved.
4191783Srmacklem *
5191783Srmacklem * This code is derived from software contributed to Berkeley by
6191783Srmacklem * Rick Macklem at The University of Guelph.
7191783Srmacklem *
8191783Srmacklem * Redistribution and use in source and binary forms, with or without
9191783Srmacklem * modification, are permitted provided that the following conditions
10191783Srmacklem * are met:
11191783Srmacklem * 1. Redistributions of source code must retain the above copyright
12191783Srmacklem *    notice, this list of conditions and the following disclaimer.
13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
14191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
15191783Srmacklem *    documentation and/or other materials provided with the distribution.
16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors
17191783Srmacklem *    may be used to endorse or promote products derived from this software
18191783Srmacklem *    without specific prior written permission.
19191783Srmacklem *
20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23191783Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30191783Srmacklem * SUCH DAMAGE.
31191783Srmacklem *
32191783Srmacklem */
33191783Srmacklem
34191783Srmacklem#include <sys/cdefs.h>
35191783Srmacklem__FBSDID("$FreeBSD$");
36191783Srmacklem
37191783Srmacklem#ifndef APPLEKEXT
38191783Srmacklem/*
39191783Srmacklem * These functions support the macros and help fiddle mbuf chains for
40191783Srmacklem * the nfs op functions. They do things like create the rpc header and
41191783Srmacklem * copy data between mbuf chains and uio lists.
42191783Srmacklem */
43191783Srmacklem#include <fs/nfs/nfsport.h>
44191783Srmacklem
45191783Srmacklemextern u_int32_t newnfs_true, newnfs_false;
46191783Srmacklemextern int nfs_pubfhset;
47284216Srmacklemextern struct nfsclienthashhead *nfsclienthash;
48284216Srmacklemextern int nfsrv_clienthashsize;
49284216Srmacklemextern struct nfslockhashhead *nfslockhash;
50284216Srmacklemextern int nfsrv_lockhashsize;
51284216Srmacklemextern struct nfssessionhash *nfssessionhash;
52284216Srmacklemextern int nfsrv_sessionhashsize;
53191783Srmacklemextern int nfsrv_useacl;
54191783Srmacklemextern uid_t nfsrv_defaultuid;
55191783Srmacklemextern gid_t nfsrv_defaultgid;
56191783Srmacklem
57191783Srmacklemchar nfs_v2pubfh[NFSX_V2FH];
58191783Srmacklemstatic nfstype newnfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
59191783Srmacklem    NFNON, NFCHR, NFNON };
60191783Srmacklemextern nfstype nfsv34_type[9];
61191783Srmacklem#endif	/* !APPLEKEXT */
62191783Srmacklem
63269398Srmacklemstatic u_int32_t nfsrv_isannfserr(u_int32_t);
64269398Srmacklem
65228260SrmacklemSYSCTL_DECL(_vfs_nfsd);
66228260Srmacklem
67228260Srmacklemstatic int	disable_checkutf8 = 0;
68228260SrmacklemSYSCTL_INT(_vfs_nfsd, OID_AUTO, disable_checkutf8, CTLFLAG_RW,
69228260Srmacklem    &disable_checkutf8, 0,
70228260Srmacklem    "Disable the NFSv4 check for a UTF8 compliant name");
71228260Srmacklem
72273877Saraujostatic int    enable_nobodycheck = 1;
73273877SaraujoSYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_nobodycheck, CTLFLAG_RW,
74273877Saraujo    &enable_nobodycheck, 0,
75273877Saraujo    "Enable the NFSv4 check when setting user nobody as owner");
76273877Saraujo
77273877Saraujostatic int    enable_nogroupcheck = 1;
78273877SaraujoSYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_nogroupcheck, CTLFLAG_RW,
79273877Saraujo    &enable_nogroupcheck, 0,
80273877Saraujo    "Enable the NFSv4 check when setting group nogroup as owner");
81273877Saraujo
82191783Srmacklemstatic char nfsrv_hexdigit(char, int *);
83191783Srmacklem
84191783Srmacklem/*
85191783Srmacklem * Maps errno values to nfs error numbers.
86191783Srmacklem * Use NFSERR_IO as the catch all for ones not specifically defined in
87269398Srmacklem * RFC 1094. (It now includes the errors added for NFSv3.)
88191783Srmacklem */
89269398Srmacklemstatic u_char nfsrv_v2errmap[NFSERR_REMOTE] = {
90191783Srmacklem  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
91191783Srmacklem  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
92191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
93269398Srmacklem  NFSERR_IO,	NFSERR_EXIST,	NFSERR_XDEV,	NFSERR_NODEV,	NFSERR_NOTDIR,
94269398Srmacklem  NFSERR_ISDIR,	NFSERR_INVAL,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
95191783Srmacklem  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
96269398Srmacklem  NFSERR_MLINK,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
97191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
98191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
99191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
100191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
101191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
102191783Srmacklem  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
103191783Srmacklem  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
104269398Srmacklem  NFSERR_REMOTE,
105191783Srmacklem};
106191783Srmacklem
107191783Srmacklem/*
108191783Srmacklem * Maps errno values to nfs error numbers.
109191783Srmacklem * Although it is not obvious whether or not NFS clients really care if
110191783Srmacklem * a returned error value is in the specified list for the procedure, the
111191783Srmacklem * safest thing to do is filter them appropriately. For Version 2, the
112191783Srmacklem * X/Open XNFS document is the only specification that defines error values
113191783Srmacklem * for each RPC (The RFC simply lists all possible error values for all RPCs),
114191783Srmacklem * so I have decided to not do this for Version 2.
115191783Srmacklem * The first entry is the default error return and the rest are the valid
116191783Srmacklem * errors for that RPC in increasing numeric order.
117191783Srmacklem */
118191783Srmacklemstatic short nfsv3err_null[] = {
119191783Srmacklem	0,
120191783Srmacklem	0,
121191783Srmacklem};
122191783Srmacklem
123191783Srmacklemstatic short nfsv3err_getattr[] = {
124191783Srmacklem	NFSERR_IO,
125191783Srmacklem	NFSERR_IO,
126191783Srmacklem	NFSERR_STALE,
127191783Srmacklem	NFSERR_BADHANDLE,
128191783Srmacklem	NFSERR_SERVERFAULT,
129191783Srmacklem	NFSERR_DELAY,
130191783Srmacklem	0,
131191783Srmacklem};
132191783Srmacklem
133191783Srmacklemstatic short nfsv3err_setattr[] = {
134191783Srmacklem	NFSERR_IO,
135191783Srmacklem	NFSERR_ACCES,
136191783Srmacklem	NFSERR_PERM,
137191783Srmacklem	NFSERR_IO,
138191783Srmacklem	NFSERR_INVAL,
139191783Srmacklem	NFSERR_NOSPC,
140191783Srmacklem	NFSERR_ROFS,
141191783Srmacklem	NFSERR_DQUOT,
142191783Srmacklem	NFSERR_STALE,
143191783Srmacklem	NFSERR_BADHANDLE,
144191783Srmacklem	NFSERR_NOT_SYNC,
145191783Srmacklem	NFSERR_SERVERFAULT,
146191783Srmacklem	NFSERR_DELAY,
147191783Srmacklem	0,
148191783Srmacklem};
149191783Srmacklem
150191783Srmacklemstatic short nfsv3err_lookup[] = {
151191783Srmacklem	NFSERR_IO,
152191783Srmacklem	NFSERR_NOENT,
153191783Srmacklem	NFSERR_ACCES,
154191783Srmacklem	NFSERR_NAMETOL,
155191783Srmacklem	NFSERR_IO,
156191783Srmacklem	NFSERR_NOTDIR,
157191783Srmacklem	NFSERR_STALE,
158191783Srmacklem	NFSERR_BADHANDLE,
159191783Srmacklem	NFSERR_SERVERFAULT,
160191783Srmacklem	NFSERR_DELAY,
161191783Srmacklem	0,
162191783Srmacklem};
163191783Srmacklem
164191783Srmacklemstatic short nfsv3err_access[] = {
165191783Srmacklem	NFSERR_IO,
166191783Srmacklem	NFSERR_IO,
167191783Srmacklem	NFSERR_STALE,
168191783Srmacklem	NFSERR_BADHANDLE,
169191783Srmacklem	NFSERR_SERVERFAULT,
170191783Srmacklem	NFSERR_DELAY,
171191783Srmacklem	0,
172191783Srmacklem};
173191783Srmacklem
174191783Srmacklemstatic short nfsv3err_readlink[] = {
175191783Srmacklem	NFSERR_IO,
176191783Srmacklem	NFSERR_IO,
177191783Srmacklem	NFSERR_ACCES,
178191783Srmacklem	NFSERR_INVAL,
179191783Srmacklem	NFSERR_STALE,
180191783Srmacklem	NFSERR_BADHANDLE,
181191783Srmacklem	NFSERR_NOTSUPP,
182191783Srmacklem	NFSERR_SERVERFAULT,
183191783Srmacklem	NFSERR_DELAY,
184191783Srmacklem	0,
185191783Srmacklem};
186191783Srmacklem
187191783Srmacklemstatic short nfsv3err_read[] = {
188191783Srmacklem	NFSERR_IO,
189191783Srmacklem	NFSERR_IO,
190191783Srmacklem	NFSERR_NXIO,
191191783Srmacklem	NFSERR_ACCES,
192191783Srmacklem	NFSERR_INVAL,
193191783Srmacklem	NFSERR_STALE,
194191783Srmacklem	NFSERR_BADHANDLE,
195191783Srmacklem	NFSERR_SERVERFAULT,
196191783Srmacklem	NFSERR_DELAY,
197191783Srmacklem	0,
198191783Srmacklem};
199191783Srmacklem
200191783Srmacklemstatic short nfsv3err_write[] = {
201191783Srmacklem	NFSERR_IO,
202191783Srmacklem	NFSERR_IO,
203191783Srmacklem	NFSERR_ACCES,
204191783Srmacklem	NFSERR_NOSPC,
205191783Srmacklem	NFSERR_INVAL,
206191783Srmacklem	NFSERR_FBIG,
207191783Srmacklem	NFSERR_ROFS,
208191783Srmacklem	NFSERR_DQUOT,
209191783Srmacklem	NFSERR_STALE,
210191783Srmacklem	NFSERR_BADHANDLE,
211191783Srmacklem	NFSERR_SERVERFAULT,
212191783Srmacklem	NFSERR_DELAY,
213191783Srmacklem	0,
214191783Srmacklem};
215191783Srmacklem
216191783Srmacklemstatic short nfsv3err_create[] = {
217191783Srmacklem	NFSERR_IO,
218191783Srmacklem	NFSERR_EXIST,
219191783Srmacklem	NFSERR_NAMETOL,
220191783Srmacklem	NFSERR_ACCES,
221191783Srmacklem	NFSERR_IO,
222191783Srmacklem	NFSERR_NOTDIR,
223191783Srmacklem	NFSERR_NOSPC,
224191783Srmacklem	NFSERR_ROFS,
225191783Srmacklem	NFSERR_DQUOT,
226191783Srmacklem	NFSERR_STALE,
227191783Srmacklem	NFSERR_BADHANDLE,
228191783Srmacklem	NFSERR_NOTSUPP,
229191783Srmacklem	NFSERR_SERVERFAULT,
230191783Srmacklem	NFSERR_DELAY,
231191783Srmacklem	0,
232191783Srmacklem};
233191783Srmacklem
234191783Srmacklemstatic short nfsv3err_mkdir[] = {
235191783Srmacklem	NFSERR_IO,
236191783Srmacklem	NFSERR_EXIST,
237191783Srmacklem	NFSERR_ACCES,
238191783Srmacklem	NFSERR_NAMETOL,
239191783Srmacklem	NFSERR_IO,
240191783Srmacklem	NFSERR_NOTDIR,
241191783Srmacklem	NFSERR_NOSPC,
242191783Srmacklem	NFSERR_ROFS,
243191783Srmacklem	NFSERR_DQUOT,
244191783Srmacklem	NFSERR_STALE,
245191783Srmacklem	NFSERR_BADHANDLE,
246191783Srmacklem	NFSERR_NOTSUPP,
247191783Srmacklem	NFSERR_SERVERFAULT,
248191783Srmacklem	NFSERR_DELAY,
249191783Srmacklem	0,
250191783Srmacklem};
251191783Srmacklem
252191783Srmacklemstatic short nfsv3err_symlink[] = {
253191783Srmacklem	NFSERR_IO,
254191783Srmacklem	NFSERR_ACCES,
255191783Srmacklem	NFSERR_EXIST,
256191783Srmacklem	NFSERR_NAMETOL,
257191783Srmacklem	NFSERR_NOSPC,
258191783Srmacklem	NFSERR_IO,
259191783Srmacklem	NFSERR_NOTDIR,
260191783Srmacklem	NFSERR_ROFS,
261191783Srmacklem	NFSERR_DQUOT,
262191783Srmacklem	NFSERR_STALE,
263191783Srmacklem	NFSERR_BADHANDLE,
264191783Srmacklem	NFSERR_NOTSUPP,
265191783Srmacklem	NFSERR_SERVERFAULT,
266191783Srmacklem	NFSERR_DELAY,
267191783Srmacklem	0,
268191783Srmacklem};
269191783Srmacklem
270191783Srmacklemstatic short nfsv3err_mknod[] = {
271191783Srmacklem	NFSERR_IO,
272191783Srmacklem	NFSERR_ACCES,
273191783Srmacklem	NFSERR_EXIST,
274191783Srmacklem	NFSERR_NAMETOL,
275191783Srmacklem	NFSERR_NOSPC,
276191783Srmacklem	NFSERR_IO,
277191783Srmacklem	NFSERR_NOTDIR,
278191783Srmacklem	NFSERR_ROFS,
279191783Srmacklem	NFSERR_DQUOT,
280191783Srmacklem	NFSERR_STALE,
281191783Srmacklem	NFSERR_BADHANDLE,
282191783Srmacklem	NFSERR_NOTSUPP,
283191783Srmacklem	NFSERR_SERVERFAULT,
284191783Srmacklem	NFSERR_DELAY,
285191783Srmacklem	NFSERR_BADTYPE,
286191783Srmacklem	0,
287191783Srmacklem};
288191783Srmacklem
289191783Srmacklemstatic short nfsv3err_remove[] = {
290191783Srmacklem	NFSERR_IO,
291191783Srmacklem	NFSERR_NOENT,
292191783Srmacklem	NFSERR_ACCES,
293191783Srmacklem	NFSERR_NAMETOL,
294191783Srmacklem	NFSERR_IO,
295191783Srmacklem	NFSERR_NOTDIR,
296191783Srmacklem	NFSERR_ROFS,
297191783Srmacklem	NFSERR_STALE,
298191783Srmacklem	NFSERR_BADHANDLE,
299191783Srmacklem	NFSERR_SERVERFAULT,
300191783Srmacklem	NFSERR_DELAY,
301191783Srmacklem	0,
302191783Srmacklem};
303191783Srmacklem
304191783Srmacklemstatic short nfsv3err_rmdir[] = {
305191783Srmacklem	NFSERR_IO,
306191783Srmacklem	NFSERR_NOENT,
307191783Srmacklem	NFSERR_ACCES,
308191783Srmacklem	NFSERR_NOTDIR,
309191783Srmacklem	NFSERR_NAMETOL,
310191783Srmacklem	NFSERR_IO,
311191783Srmacklem	NFSERR_EXIST,
312191783Srmacklem	NFSERR_INVAL,
313191783Srmacklem	NFSERR_ROFS,
314191783Srmacklem	NFSERR_NOTEMPTY,
315191783Srmacklem	NFSERR_STALE,
316191783Srmacklem	NFSERR_BADHANDLE,
317191783Srmacklem	NFSERR_NOTSUPP,
318191783Srmacklem	NFSERR_SERVERFAULT,
319191783Srmacklem	NFSERR_DELAY,
320191783Srmacklem	0,
321191783Srmacklem};
322191783Srmacklem
323191783Srmacklemstatic short nfsv3err_rename[] = {
324191783Srmacklem	NFSERR_IO,
325191783Srmacklem	NFSERR_NOENT,
326191783Srmacklem	NFSERR_ACCES,
327191783Srmacklem	NFSERR_EXIST,
328191783Srmacklem	NFSERR_NAMETOL,
329191783Srmacklem	NFSERR_XDEV,
330191783Srmacklem	NFSERR_IO,
331191783Srmacklem	NFSERR_NOTDIR,
332191783Srmacklem	NFSERR_ISDIR,
333191783Srmacklem	NFSERR_INVAL,
334191783Srmacklem	NFSERR_NOSPC,
335191783Srmacklem	NFSERR_ROFS,
336191783Srmacklem	NFSERR_MLINK,
337191783Srmacklem	NFSERR_NOTEMPTY,
338191783Srmacklem	NFSERR_DQUOT,
339191783Srmacklem	NFSERR_STALE,
340191783Srmacklem	NFSERR_BADHANDLE,
341191783Srmacklem	NFSERR_NOTSUPP,
342191783Srmacklem	NFSERR_SERVERFAULT,
343191783Srmacklem	NFSERR_DELAY,
344191783Srmacklem	0,
345191783Srmacklem};
346191783Srmacklem
347191783Srmacklemstatic short nfsv3err_link[] = {
348191783Srmacklem	NFSERR_IO,
349191783Srmacklem	NFSERR_ACCES,
350191783Srmacklem	NFSERR_EXIST,
351191783Srmacklem	NFSERR_NAMETOL,
352191783Srmacklem	NFSERR_IO,
353191783Srmacklem	NFSERR_XDEV,
354191783Srmacklem	NFSERR_NOTDIR,
355191783Srmacklem	NFSERR_INVAL,
356191783Srmacklem	NFSERR_NOSPC,
357191783Srmacklem	NFSERR_ROFS,
358191783Srmacklem	NFSERR_MLINK,
359191783Srmacklem	NFSERR_DQUOT,
360191783Srmacklem	NFSERR_STALE,
361191783Srmacklem	NFSERR_BADHANDLE,
362191783Srmacklem	NFSERR_NOTSUPP,
363191783Srmacklem	NFSERR_SERVERFAULT,
364191783Srmacklem	NFSERR_DELAY,
365191783Srmacklem	0,
366191783Srmacklem};
367191783Srmacklem
368191783Srmacklemstatic short nfsv3err_readdir[] = {
369191783Srmacklem	NFSERR_IO,
370191783Srmacklem	NFSERR_ACCES,
371191783Srmacklem	NFSERR_NOTDIR,
372191783Srmacklem	NFSERR_IO,
373191783Srmacklem	NFSERR_STALE,
374191783Srmacklem	NFSERR_BADHANDLE,
375191783Srmacklem	NFSERR_BAD_COOKIE,
376191783Srmacklem	NFSERR_TOOSMALL,
377191783Srmacklem	NFSERR_SERVERFAULT,
378191783Srmacklem	NFSERR_DELAY,
379191783Srmacklem	0,
380191783Srmacklem};
381191783Srmacklem
382191783Srmacklemstatic short nfsv3err_readdirplus[] = {
383191783Srmacklem	NFSERR_IO,
384191783Srmacklem	NFSERR_ACCES,
385191783Srmacklem	NFSERR_NOTDIR,
386191783Srmacklem	NFSERR_IO,
387191783Srmacklem	NFSERR_STALE,
388191783Srmacklem	NFSERR_BADHANDLE,
389191783Srmacklem	NFSERR_BAD_COOKIE,
390191783Srmacklem	NFSERR_NOTSUPP,
391191783Srmacklem	NFSERR_TOOSMALL,
392191783Srmacklem	NFSERR_SERVERFAULT,
393191783Srmacklem	NFSERR_DELAY,
394191783Srmacklem	0,
395191783Srmacklem};
396191783Srmacklem
397191783Srmacklemstatic short nfsv3err_fsstat[] = {
398191783Srmacklem	NFSERR_IO,
399191783Srmacklem	NFSERR_IO,
400191783Srmacklem	NFSERR_STALE,
401191783Srmacklem	NFSERR_BADHANDLE,
402191783Srmacklem	NFSERR_SERVERFAULT,
403191783Srmacklem	NFSERR_DELAY,
404191783Srmacklem	0,
405191783Srmacklem};
406191783Srmacklem
407191783Srmacklemstatic short nfsv3err_fsinfo[] = {
408191783Srmacklem	NFSERR_STALE,
409191783Srmacklem	NFSERR_STALE,
410191783Srmacklem	NFSERR_BADHANDLE,
411191783Srmacklem	NFSERR_SERVERFAULT,
412191783Srmacklem	NFSERR_DELAY,
413191783Srmacklem	0,
414191783Srmacklem};
415191783Srmacklem
416191783Srmacklemstatic short nfsv3err_pathconf[] = {
417191783Srmacklem	NFSERR_STALE,
418191783Srmacklem	NFSERR_STALE,
419191783Srmacklem	NFSERR_BADHANDLE,
420191783Srmacklem	NFSERR_SERVERFAULT,
421191783Srmacklem	NFSERR_DELAY,
422191783Srmacklem	0,
423191783Srmacklem};
424191783Srmacklem
425191783Srmacklemstatic short nfsv3err_commit[] = {
426191783Srmacklem	NFSERR_IO,
427191783Srmacklem	NFSERR_IO,
428191783Srmacklem	NFSERR_STALE,
429191783Srmacklem	NFSERR_BADHANDLE,
430191783Srmacklem	NFSERR_SERVERFAULT,
431191783Srmacklem	NFSERR_DELAY,
432191783Srmacklem	0,
433191783Srmacklem};
434191783Srmacklem
435191783Srmacklemstatic short *nfsrv_v3errmap[] = {
436191783Srmacklem	nfsv3err_null,
437191783Srmacklem	nfsv3err_getattr,
438191783Srmacklem	nfsv3err_setattr,
439191783Srmacklem	nfsv3err_lookup,
440191783Srmacklem	nfsv3err_access,
441191783Srmacklem	nfsv3err_readlink,
442191783Srmacklem	nfsv3err_read,
443191783Srmacklem	nfsv3err_write,
444191783Srmacklem	nfsv3err_create,
445191783Srmacklem	nfsv3err_mkdir,
446191783Srmacklem	nfsv3err_symlink,
447191783Srmacklem	nfsv3err_mknod,
448191783Srmacklem	nfsv3err_remove,
449191783Srmacklem	nfsv3err_rmdir,
450191783Srmacklem	nfsv3err_rename,
451191783Srmacklem	nfsv3err_link,
452191783Srmacklem	nfsv3err_readdir,
453191783Srmacklem	nfsv3err_readdirplus,
454191783Srmacklem	nfsv3err_fsstat,
455191783Srmacklem	nfsv3err_fsinfo,
456191783Srmacklem	nfsv3err_pathconf,
457191783Srmacklem	nfsv3err_commit,
458191783Srmacklem};
459191783Srmacklem
460191783Srmacklem/*
461191783Srmacklem * And the same for V4.
462191783Srmacklem */
463191783Srmacklemstatic short nfsv4err_null[] = {
464191783Srmacklem	0,
465191783Srmacklem	0,
466191783Srmacklem};
467191783Srmacklem
468191783Srmacklemstatic short nfsv4err_access[] = {
469191783Srmacklem	NFSERR_IO,
470191783Srmacklem	NFSERR_ACCES,
471191783Srmacklem	NFSERR_BADHANDLE,
472191783Srmacklem	NFSERR_BADXDR,
473191783Srmacklem	NFSERR_DELAY,
474191783Srmacklem	NFSERR_FHEXPIRED,
475191783Srmacklem	NFSERR_INVAL,
476191783Srmacklem	NFSERR_IO,
477191783Srmacklem	NFSERR_MOVED,
478191783Srmacklem	NFSERR_NOFILEHANDLE,
479191783Srmacklem	NFSERR_RESOURCE,
480191783Srmacklem	NFSERR_SERVERFAULT,
481191783Srmacklem	NFSERR_STALE,
482191783Srmacklem	0,
483191783Srmacklem};
484191783Srmacklem
485191783Srmacklemstatic short nfsv4err_close[] = {
486191783Srmacklem	NFSERR_EXPIRED,
487191783Srmacklem	NFSERR_ADMINREVOKED,
488191783Srmacklem	NFSERR_BADHANDLE,
489191783Srmacklem	NFSERR_BADSEQID,
490191783Srmacklem	NFSERR_BADSTATEID,
491191783Srmacklem	NFSERR_BADXDR,
492191783Srmacklem	NFSERR_DELAY,
493191783Srmacklem	NFSERR_EXPIRED,
494191783Srmacklem	NFSERR_FHEXPIRED,
495191783Srmacklem	NFSERR_INVAL,
496191783Srmacklem	NFSERR_ISDIR,
497191783Srmacklem	NFSERR_LEASEMOVED,
498191783Srmacklem	NFSERR_LOCKSHELD,
499191783Srmacklem	NFSERR_MOVED,
500191783Srmacklem	NFSERR_NOFILEHANDLE,
501191783Srmacklem	NFSERR_OLDSTATEID,
502191783Srmacklem	NFSERR_RESOURCE,
503191783Srmacklem	NFSERR_SERVERFAULT,
504191783Srmacklem	NFSERR_STALE,
505191783Srmacklem	NFSERR_STALESTATEID,
506191783Srmacklem	0,
507191783Srmacklem};
508191783Srmacklem
509191783Srmacklemstatic short nfsv4err_commit[] = {
510191783Srmacklem	NFSERR_IO,
511191783Srmacklem	NFSERR_ACCES,
512191783Srmacklem	NFSERR_BADHANDLE,
513191783Srmacklem	NFSERR_BADXDR,
514191783Srmacklem	NFSERR_FHEXPIRED,
515191783Srmacklem	NFSERR_INVAL,
516191783Srmacklem	NFSERR_IO,
517191783Srmacklem	NFSERR_ISDIR,
518191783Srmacklem	NFSERR_MOVED,
519191783Srmacklem	NFSERR_NOFILEHANDLE,
520191783Srmacklem	NFSERR_RESOURCE,
521191783Srmacklem	NFSERR_ROFS,
522191783Srmacklem	NFSERR_SERVERFAULT,
523191783Srmacklem	NFSERR_STALE,
524191783Srmacklem	0,
525191783Srmacklem};
526191783Srmacklem
527191783Srmacklemstatic short nfsv4err_create[] = {
528191783Srmacklem	NFSERR_IO,
529191783Srmacklem	NFSERR_ACCES,
530191783Srmacklem	NFSERR_ATTRNOTSUPP,
531191783Srmacklem	NFSERR_BADCHAR,
532191783Srmacklem	NFSERR_BADHANDLE,
533191783Srmacklem	NFSERR_BADNAME,
534191783Srmacklem	NFSERR_BADOWNER,
535191783Srmacklem	NFSERR_BADTYPE,
536191783Srmacklem	NFSERR_BADXDR,
537191783Srmacklem	NFSERR_DELAY,
538191783Srmacklem	NFSERR_DQUOT,
539191783Srmacklem	NFSERR_EXIST,
540191783Srmacklem	NFSERR_FHEXPIRED,
541191783Srmacklem	NFSERR_INVAL,
542191783Srmacklem	NFSERR_IO,
543191783Srmacklem	NFSERR_MOVED,
544191783Srmacklem	NFSERR_NAMETOL,
545191783Srmacklem	NFSERR_NOFILEHANDLE,
546191783Srmacklem	NFSERR_NOSPC,
547191783Srmacklem	NFSERR_NOTDIR,
548191783Srmacklem	NFSERR_PERM,
549191783Srmacklem	NFSERR_RESOURCE,
550191783Srmacklem	NFSERR_ROFS,
551191783Srmacklem	NFSERR_SERVERFAULT,
552191783Srmacklem	NFSERR_STALE,
553191783Srmacklem	0,
554191783Srmacklem};
555191783Srmacklem
556191783Srmacklemstatic short nfsv4err_delegpurge[] = {
557191783Srmacklem	NFSERR_SERVERFAULT,
558191783Srmacklem	NFSERR_BADXDR,
559191783Srmacklem	NFSERR_NOTSUPP,
560191783Srmacklem	NFSERR_LEASEMOVED,
561191783Srmacklem	NFSERR_MOVED,
562191783Srmacklem	NFSERR_RESOURCE,
563191783Srmacklem	NFSERR_SERVERFAULT,
564191783Srmacklem	NFSERR_STALECLIENTID,
565191783Srmacklem	0,
566191783Srmacklem};
567191783Srmacklem
568191783Srmacklemstatic short nfsv4err_delegreturn[] = {
569191783Srmacklem	NFSERR_SERVERFAULT,
570191783Srmacklem	NFSERR_ADMINREVOKED,
571191783Srmacklem	NFSERR_BADSTATEID,
572191783Srmacklem	NFSERR_BADXDR,
573191783Srmacklem	NFSERR_EXPIRED,
574191783Srmacklem	NFSERR_INVAL,
575191783Srmacklem	NFSERR_LEASEMOVED,
576191783Srmacklem	NFSERR_MOVED,
577191783Srmacklem	NFSERR_NOFILEHANDLE,
578191783Srmacklem	NFSERR_NOTSUPP,
579191783Srmacklem	NFSERR_OLDSTATEID,
580191783Srmacklem	NFSERR_RESOURCE,
581191783Srmacklem	NFSERR_SERVERFAULT,
582191783Srmacklem	NFSERR_STALE,
583191783Srmacklem	NFSERR_STALESTATEID,
584191783Srmacklem	0,
585191783Srmacklem};
586191783Srmacklem
587191783Srmacklemstatic short nfsv4err_getattr[] = {
588191783Srmacklem	NFSERR_IO,
589191783Srmacklem	NFSERR_ACCES,
590191783Srmacklem	NFSERR_BADHANDLE,
591191783Srmacklem	NFSERR_BADXDR,
592191783Srmacklem	NFSERR_DELAY,
593191783Srmacklem	NFSERR_FHEXPIRED,
594191783Srmacklem	NFSERR_INVAL,
595191783Srmacklem	NFSERR_IO,
596191783Srmacklem	NFSERR_MOVED,
597191783Srmacklem	NFSERR_NOFILEHANDLE,
598191783Srmacklem	NFSERR_RESOURCE,
599191783Srmacklem	NFSERR_SERVERFAULT,
600191783Srmacklem	NFSERR_STALE,
601191783Srmacklem	0,
602191783Srmacklem};
603191783Srmacklem
604191783Srmacklemstatic short nfsv4err_getfh[] = {
605191783Srmacklem	NFSERR_BADHANDLE,
606191783Srmacklem	NFSERR_BADHANDLE,
607191783Srmacklem	NFSERR_FHEXPIRED,
608191783Srmacklem	NFSERR_MOVED,
609191783Srmacklem	NFSERR_NOFILEHANDLE,
610191783Srmacklem	NFSERR_RESOURCE,
611191783Srmacklem	NFSERR_SERVERFAULT,
612191783Srmacklem	NFSERR_STALE,
613191783Srmacklem	0,
614191783Srmacklem};
615191783Srmacklem
616191783Srmacklemstatic short nfsv4err_link[] = {
617191783Srmacklem	NFSERR_IO,
618191783Srmacklem	NFSERR_ACCES,
619191783Srmacklem	NFSERR_BADCHAR,
620191783Srmacklem	NFSERR_BADHANDLE,
621191783Srmacklem	NFSERR_BADNAME,
622191783Srmacklem	NFSERR_BADXDR,
623191783Srmacklem	NFSERR_DELAY,
624191783Srmacklem	NFSERR_DQUOT,
625191783Srmacklem	NFSERR_EXIST,
626191783Srmacklem	NFSERR_FHEXPIRED,
627191783Srmacklem	NFSERR_FILEOPEN,
628191783Srmacklem	NFSERR_INVAL,
629191783Srmacklem	NFSERR_IO,
630191783Srmacklem	NFSERR_ISDIR,
631191783Srmacklem	NFSERR_MLINK,
632191783Srmacklem	NFSERR_MOVED,
633191783Srmacklem	NFSERR_NAMETOL,
634191783Srmacklem	NFSERR_NOENT,
635191783Srmacklem	NFSERR_NOFILEHANDLE,
636191783Srmacklem	NFSERR_NOSPC,
637191783Srmacklem	NFSERR_NOTDIR,
638191783Srmacklem	NFSERR_NOTSUPP,
639191783Srmacklem	NFSERR_RESOURCE,
640191783Srmacklem	NFSERR_ROFS,
641191783Srmacklem	NFSERR_SERVERFAULT,
642191783Srmacklem	NFSERR_STALE,
643191783Srmacklem	NFSERR_WRONGSEC,
644191783Srmacklem	NFSERR_XDEV,
645191783Srmacklem	0,
646191783Srmacklem};
647191783Srmacklem
648191783Srmacklemstatic short nfsv4err_lock[] = {
649191783Srmacklem	NFSERR_SERVERFAULT,
650191783Srmacklem	NFSERR_ACCES,
651191783Srmacklem	NFSERR_ADMINREVOKED,
652191783Srmacklem	NFSERR_BADHANDLE,
653191783Srmacklem	NFSERR_BADRANGE,
654191783Srmacklem	NFSERR_BADSEQID,
655191783Srmacklem	NFSERR_BADSTATEID,
656191783Srmacklem	NFSERR_BADXDR,
657191783Srmacklem	NFSERR_DEADLOCK,
658191783Srmacklem	NFSERR_DELAY,
659191783Srmacklem	NFSERR_DENIED,
660191783Srmacklem	NFSERR_EXPIRED,
661191783Srmacklem	NFSERR_FHEXPIRED,
662191783Srmacklem	NFSERR_GRACE,
663191783Srmacklem	NFSERR_INVAL,
664191783Srmacklem	NFSERR_ISDIR,
665191783Srmacklem	NFSERR_LEASEMOVED,
666191783Srmacklem	NFSERR_LOCKNOTSUPP,
667191783Srmacklem	NFSERR_LOCKRANGE,
668191783Srmacklem	NFSERR_MOVED,
669191783Srmacklem	NFSERR_NOFILEHANDLE,
670191783Srmacklem	NFSERR_NOGRACE,
671191783Srmacklem	NFSERR_OLDSTATEID,
672191783Srmacklem	NFSERR_OPENMODE,
673191783Srmacklem	NFSERR_RECLAIMBAD,
674191783Srmacklem	NFSERR_RECLAIMCONFLICT,
675191783Srmacklem	NFSERR_RESOURCE,
676191783Srmacklem	NFSERR_SERVERFAULT,
677191783Srmacklem	NFSERR_STALE,
678191783Srmacklem	NFSERR_STALECLIENTID,
679191783Srmacklem	NFSERR_STALESTATEID,
680191783Srmacklem	0,
681191783Srmacklem};
682191783Srmacklem
683191783Srmacklemstatic short nfsv4err_lockt[] = {
684191783Srmacklem	NFSERR_SERVERFAULT,
685191783Srmacklem	NFSERR_ACCES,
686191783Srmacklem	NFSERR_BADHANDLE,
687191783Srmacklem	NFSERR_BADRANGE,
688191783Srmacklem	NFSERR_BADXDR,
689191783Srmacklem	NFSERR_DELAY,
690191783Srmacklem	NFSERR_DENIED,
691191783Srmacklem	NFSERR_FHEXPIRED,
692191783Srmacklem	NFSERR_GRACE,
693191783Srmacklem	NFSERR_INVAL,
694191783Srmacklem	NFSERR_ISDIR,
695191783Srmacklem	NFSERR_LEASEMOVED,
696191783Srmacklem	NFSERR_LOCKRANGE,
697191783Srmacklem	NFSERR_MOVED,
698191783Srmacklem	NFSERR_NOFILEHANDLE,
699191783Srmacklem	NFSERR_RESOURCE,
700191783Srmacklem	NFSERR_SERVERFAULT,
701191783Srmacklem	NFSERR_STALE,
702191783Srmacklem	NFSERR_STALECLIENTID,
703191783Srmacklem	0,
704191783Srmacklem};
705191783Srmacklem
706191783Srmacklemstatic short nfsv4err_locku[] = {
707191783Srmacklem	NFSERR_SERVERFAULT,
708191783Srmacklem	NFSERR_ACCES,
709191783Srmacklem	NFSERR_ADMINREVOKED,
710191783Srmacklem	NFSERR_BADHANDLE,
711191783Srmacklem	NFSERR_BADRANGE,
712191783Srmacklem	NFSERR_BADSEQID,
713191783Srmacklem	NFSERR_BADSTATEID,
714191783Srmacklem	NFSERR_BADXDR,
715191783Srmacklem	NFSERR_EXPIRED,
716191783Srmacklem	NFSERR_FHEXPIRED,
717191783Srmacklem	NFSERR_GRACE,
718191783Srmacklem	NFSERR_INVAL,
719191783Srmacklem	NFSERR_ISDIR,
720191783Srmacklem	NFSERR_LEASEMOVED,
721191783Srmacklem	NFSERR_LOCKRANGE,
722191783Srmacklem	NFSERR_MOVED,
723191783Srmacklem	NFSERR_NOFILEHANDLE,
724191783Srmacklem	NFSERR_OLDSTATEID,
725191783Srmacklem	NFSERR_RESOURCE,
726191783Srmacklem	NFSERR_SERVERFAULT,
727191783Srmacklem	NFSERR_STALE,
728191783Srmacklem	NFSERR_STALESTATEID,
729191783Srmacklem	0,
730191783Srmacklem};
731191783Srmacklem
732191783Srmacklemstatic short nfsv4err_lookup[] = {
733191783Srmacklem	NFSERR_IO,
734191783Srmacklem	NFSERR_ACCES,
735191783Srmacklem	NFSERR_BADCHAR,
736191783Srmacklem	NFSERR_BADHANDLE,
737191783Srmacklem	NFSERR_BADNAME,
738191783Srmacklem	NFSERR_BADXDR,
739191783Srmacklem	NFSERR_FHEXPIRED,
740191783Srmacklem	NFSERR_INVAL,
741191783Srmacklem	NFSERR_IO,
742191783Srmacklem	NFSERR_MOVED,
743191783Srmacklem	NFSERR_NAMETOL,
744191783Srmacklem	NFSERR_NOENT,
745191783Srmacklem	NFSERR_NOFILEHANDLE,
746191783Srmacklem	NFSERR_NOTDIR,
747191783Srmacklem	NFSERR_RESOURCE,
748191783Srmacklem	NFSERR_SERVERFAULT,
749191783Srmacklem	NFSERR_STALE,
750191783Srmacklem	NFSERR_SYMLINK,
751191783Srmacklem	NFSERR_WRONGSEC,
752191783Srmacklem	0,
753191783Srmacklem};
754191783Srmacklem
755191783Srmacklemstatic short nfsv4err_lookupp[] = {
756191783Srmacklem	NFSERR_IO,
757191783Srmacklem	NFSERR_ACCES,
758191783Srmacklem	NFSERR_BADHANDLE,
759191783Srmacklem	NFSERR_FHEXPIRED,
760191783Srmacklem	NFSERR_IO,
761191783Srmacklem	NFSERR_MOVED,
762191783Srmacklem	NFSERR_NOENT,
763191783Srmacklem	NFSERR_NOFILEHANDLE,
764191783Srmacklem	NFSERR_NOTDIR,
765191783Srmacklem	NFSERR_RESOURCE,
766191783Srmacklem	NFSERR_SERVERFAULT,
767191783Srmacklem	NFSERR_STALE,
768191783Srmacklem	0,
769191783Srmacklem};
770191783Srmacklem
771191783Srmacklemstatic short nfsv4err_nverify[] = {
772191783Srmacklem	NFSERR_IO,
773191783Srmacklem	NFSERR_ACCES,
774191783Srmacklem	NFSERR_ATTRNOTSUPP,
775191783Srmacklem	NFSERR_BADCHAR,
776191783Srmacklem	NFSERR_BADHANDLE,
777191783Srmacklem	NFSERR_BADXDR,
778191783Srmacklem	NFSERR_DELAY,
779191783Srmacklem	NFSERR_FHEXPIRED,
780191783Srmacklem	NFSERR_INVAL,
781191783Srmacklem	NFSERR_IO,
782191783Srmacklem	NFSERR_MOVED,
783191783Srmacklem	NFSERR_NOFILEHANDLE,
784191783Srmacklem	NFSERR_RESOURCE,
785191783Srmacklem	NFSERR_SAME,
786191783Srmacklem	NFSERR_SERVERFAULT,
787191783Srmacklem	NFSERR_STALE,
788191783Srmacklem	0,
789191783Srmacklem};
790191783Srmacklem
791191783Srmacklemstatic short nfsv4err_open[] = {
792191783Srmacklem	NFSERR_IO,
793191783Srmacklem	NFSERR_ACCES,
794191783Srmacklem	NFSERR_ADMINREVOKED,
795191783Srmacklem	NFSERR_ATTRNOTSUPP,
796191783Srmacklem	NFSERR_BADCHAR,
797191783Srmacklem	NFSERR_BADHANDLE,
798191783Srmacklem	NFSERR_BADNAME,
799191783Srmacklem	NFSERR_BADOWNER,
800191783Srmacklem	NFSERR_BADSEQID,
801191783Srmacklem	NFSERR_BADXDR,
802191783Srmacklem	NFSERR_DELAY,
803191783Srmacklem	NFSERR_DQUOT,
804191783Srmacklem	NFSERR_EXIST,
805191783Srmacklem	NFSERR_EXPIRED,
806191783Srmacklem	NFSERR_FHEXPIRED,
807191783Srmacklem	NFSERR_GRACE,
808191783Srmacklem	NFSERR_IO,
809191783Srmacklem	NFSERR_INVAL,
810191783Srmacklem	NFSERR_ISDIR,
811191783Srmacklem	NFSERR_LEASEMOVED,
812191783Srmacklem	NFSERR_MOVED,
813191783Srmacklem	NFSERR_NAMETOL,
814191783Srmacklem	NFSERR_NOENT,
815191783Srmacklem	NFSERR_NOFILEHANDLE,
816191783Srmacklem	NFSERR_NOGRACE,
817191783Srmacklem	NFSERR_NOSPC,
818191783Srmacklem	NFSERR_NOTDIR,
819191783Srmacklem	NFSERR_NOTSUPP,
820191783Srmacklem	NFSERR_PERM,
821191783Srmacklem	NFSERR_RECLAIMBAD,
822191783Srmacklem	NFSERR_RECLAIMCONFLICT,
823191783Srmacklem	NFSERR_RESOURCE,
824191783Srmacklem	NFSERR_ROFS,
825191783Srmacklem	NFSERR_SERVERFAULT,
826191783Srmacklem	NFSERR_SHAREDENIED,
827191783Srmacklem	NFSERR_STALE,
828191783Srmacklem	NFSERR_STALECLIENTID,
829191783Srmacklem	NFSERR_SYMLINK,
830191783Srmacklem	NFSERR_WRONGSEC,
831191783Srmacklem	0,
832191783Srmacklem};
833191783Srmacklem
834191783Srmacklemstatic short nfsv4err_openattr[] = {
835191783Srmacklem	NFSERR_IO,
836191783Srmacklem	NFSERR_ACCES,
837191783Srmacklem	NFSERR_BADHANDLE,
838191783Srmacklem	NFSERR_BADXDR,
839191783Srmacklem	NFSERR_DELAY,
840191783Srmacklem	NFSERR_DQUOT,
841191783Srmacklem	NFSERR_FHEXPIRED,
842191783Srmacklem	NFSERR_IO,
843191783Srmacklem	NFSERR_MOVED,
844191783Srmacklem	NFSERR_NOENT,
845191783Srmacklem	NFSERR_NOFILEHANDLE,
846191783Srmacklem	NFSERR_NOSPC,
847191783Srmacklem	NFSERR_NOTSUPP,
848191783Srmacklem	NFSERR_RESOURCE,
849191783Srmacklem	NFSERR_ROFS,
850191783Srmacklem	NFSERR_SERVERFAULT,
851191783Srmacklem	NFSERR_STALE,
852191783Srmacklem	0,
853191783Srmacklem};
854191783Srmacklem
855191783Srmacklemstatic short nfsv4err_openconfirm[] = {
856191783Srmacklem	NFSERR_SERVERFAULT,
857191783Srmacklem	NFSERR_ADMINREVOKED,
858191783Srmacklem	NFSERR_BADHANDLE,
859191783Srmacklem	NFSERR_BADSEQID,
860191783Srmacklem	NFSERR_BADSTATEID,
861191783Srmacklem	NFSERR_BADXDR,
862191783Srmacklem	NFSERR_EXPIRED,
863191783Srmacklem	NFSERR_FHEXPIRED,
864191783Srmacklem	NFSERR_INVAL,
865191783Srmacklem	NFSERR_ISDIR,
866191783Srmacklem	NFSERR_MOVED,
867191783Srmacklem	NFSERR_NOFILEHANDLE,
868191783Srmacklem	NFSERR_OLDSTATEID,
869191783Srmacklem	NFSERR_RESOURCE,
870191783Srmacklem	NFSERR_SERVERFAULT,
871191783Srmacklem	NFSERR_STALE,
872191783Srmacklem	NFSERR_STALESTATEID,
873191783Srmacklem	0,
874191783Srmacklem};
875191783Srmacklem
876191783Srmacklemstatic short nfsv4err_opendowngrade[] = {
877191783Srmacklem	NFSERR_SERVERFAULT,
878191783Srmacklem	NFSERR_ADMINREVOKED,
879191783Srmacklem	NFSERR_BADHANDLE,
880191783Srmacklem	NFSERR_BADSEQID,
881191783Srmacklem	NFSERR_BADSTATEID,
882191783Srmacklem	NFSERR_BADXDR,
883191783Srmacklem	NFSERR_EXPIRED,
884191783Srmacklem	NFSERR_FHEXPIRED,
885191783Srmacklem	NFSERR_INVAL,
886191783Srmacklem	NFSERR_MOVED,
887191783Srmacklem	NFSERR_NOFILEHANDLE,
888191783Srmacklem	NFSERR_OLDSTATEID,
889191783Srmacklem	NFSERR_RESOURCE,
890191783Srmacklem	NFSERR_SERVERFAULT,
891191783Srmacklem	NFSERR_STALE,
892191783Srmacklem	NFSERR_STALESTATEID,
893191783Srmacklem	0,
894191783Srmacklem};
895191783Srmacklem
896191783Srmacklemstatic short nfsv4err_putfh[] = {
897191783Srmacklem	NFSERR_SERVERFAULT,
898191783Srmacklem	NFSERR_BADHANDLE,
899191783Srmacklem	NFSERR_BADXDR,
900191783Srmacklem	NFSERR_FHEXPIRED,
901191783Srmacklem	NFSERR_MOVED,
902191783Srmacklem	NFSERR_RESOURCE,
903191783Srmacklem	NFSERR_SERVERFAULT,
904191783Srmacklem	NFSERR_STALE,
905191783Srmacklem	NFSERR_WRONGSEC,
906191783Srmacklem	0,
907191783Srmacklem};
908191783Srmacklem
909191783Srmacklemstatic short nfsv4err_putpubfh[] = {
910191783Srmacklem	NFSERR_SERVERFAULT,
911191783Srmacklem	NFSERR_RESOURCE,
912191783Srmacklem	NFSERR_SERVERFAULT,
913191783Srmacklem	NFSERR_WRONGSEC,
914191783Srmacklem	0,
915191783Srmacklem};
916191783Srmacklem
917191783Srmacklemstatic short nfsv4err_putrootfh[] = {
918191783Srmacklem	NFSERR_SERVERFAULT,
919191783Srmacklem	NFSERR_RESOURCE,
920191783Srmacklem	NFSERR_SERVERFAULT,
921191783Srmacklem	NFSERR_WRONGSEC,
922191783Srmacklem	0,
923191783Srmacklem};
924191783Srmacklem
925191783Srmacklemstatic short nfsv4err_read[] = {
926191783Srmacklem	NFSERR_IO,
927191783Srmacklem	NFSERR_ACCES,
928191783Srmacklem	NFSERR_ADMINREVOKED,
929191783Srmacklem	NFSERR_BADHANDLE,
930191783Srmacklem	NFSERR_BADSTATEID,
931191783Srmacklem	NFSERR_BADXDR,
932191783Srmacklem	NFSERR_DELAY,
933191783Srmacklem	NFSERR_EXPIRED,
934191783Srmacklem	NFSERR_FHEXPIRED,
935191783Srmacklem	NFSERR_GRACE,
936191783Srmacklem	NFSERR_IO,
937191783Srmacklem	NFSERR_INVAL,
938191783Srmacklem	NFSERR_ISDIR,
939191783Srmacklem	NFSERR_LEASEMOVED,
940191783Srmacklem	NFSERR_LOCKED,
941191783Srmacklem	NFSERR_MOVED,
942191783Srmacklem	NFSERR_NOFILEHANDLE,
943191783Srmacklem	NFSERR_NXIO,
944191783Srmacklem	NFSERR_OLDSTATEID,
945191783Srmacklem	NFSERR_OPENMODE,
946191783Srmacklem	NFSERR_RESOURCE,
947191783Srmacklem	NFSERR_SERVERFAULT,
948191783Srmacklem	NFSERR_STALE,
949191783Srmacklem	NFSERR_STALESTATEID,
950191783Srmacklem	0,
951191783Srmacklem};
952191783Srmacklem
953191783Srmacklemstatic short nfsv4err_readdir[] = {
954191783Srmacklem	NFSERR_IO,
955191783Srmacklem	NFSERR_ACCES,
956191783Srmacklem	NFSERR_BADHANDLE,
957191783Srmacklem	NFSERR_BAD_COOKIE,
958191783Srmacklem	NFSERR_BADXDR,
959191783Srmacklem	NFSERR_DELAY,
960191783Srmacklem	NFSERR_FHEXPIRED,
961191783Srmacklem	NFSERR_INVAL,
962191783Srmacklem	NFSERR_IO,
963191783Srmacklem	NFSERR_MOVED,
964191783Srmacklem	NFSERR_NOFILEHANDLE,
965191783Srmacklem	NFSERR_NOTDIR,
966191783Srmacklem	NFSERR_NOTSAME,
967191783Srmacklem	NFSERR_RESOURCE,
968191783Srmacklem	NFSERR_SERVERFAULT,
969191783Srmacklem	NFSERR_STALE,
970191783Srmacklem	NFSERR_TOOSMALL,
971191783Srmacklem	0,
972191783Srmacklem};
973191783Srmacklem
974191783Srmacklemstatic short nfsv4err_readlink[] = {
975191783Srmacklem	NFSERR_IO,
976191783Srmacklem	NFSERR_ACCES,
977191783Srmacklem	NFSERR_BADHANDLE,
978191783Srmacklem	NFSERR_DELAY,
979191783Srmacklem	NFSERR_FHEXPIRED,
980191783Srmacklem	NFSERR_INVAL,
981191783Srmacklem	NFSERR_IO,
982191783Srmacklem	NFSERR_ISDIR,
983191783Srmacklem	NFSERR_MOVED,
984191783Srmacklem	NFSERR_NOFILEHANDLE,
985191783Srmacklem	NFSERR_NOTSUPP,
986191783Srmacklem	NFSERR_RESOURCE,
987191783Srmacklem	NFSERR_SERVERFAULT,
988191783Srmacklem	NFSERR_STALE,
989191783Srmacklem	0,
990191783Srmacklem};
991191783Srmacklem
992191783Srmacklemstatic short nfsv4err_remove[] = {
993191783Srmacklem	NFSERR_IO,
994191783Srmacklem	NFSERR_ACCES,
995191783Srmacklem	NFSERR_BADCHAR,
996191783Srmacklem	NFSERR_BADHANDLE,
997191783Srmacklem	NFSERR_BADNAME,
998191783Srmacklem	NFSERR_BADXDR,
999191783Srmacklem	NFSERR_DELAY,
1000191783Srmacklem	NFSERR_FHEXPIRED,
1001191783Srmacklem	NFSERR_FILEOPEN,
1002191783Srmacklem	NFSERR_INVAL,
1003191783Srmacklem	NFSERR_IO,
1004191783Srmacklem	NFSERR_MOVED,
1005191783Srmacklem	NFSERR_NAMETOL,
1006191783Srmacklem	NFSERR_NOENT,
1007191783Srmacklem	NFSERR_NOFILEHANDLE,
1008191783Srmacklem	NFSERR_NOTDIR,
1009191783Srmacklem	NFSERR_NOTEMPTY,
1010191783Srmacklem	NFSERR_RESOURCE,
1011191783Srmacklem	NFSERR_ROFS,
1012191783Srmacklem	NFSERR_SERVERFAULT,
1013191783Srmacklem	NFSERR_STALE,
1014191783Srmacklem	0,
1015191783Srmacklem};
1016191783Srmacklem
1017191783Srmacklemstatic short nfsv4err_rename[] = {
1018191783Srmacklem	NFSERR_IO,
1019191783Srmacklem	NFSERR_ACCES,
1020191783Srmacklem	NFSERR_BADCHAR,
1021191783Srmacklem	NFSERR_BADHANDLE,
1022191783Srmacklem	NFSERR_BADNAME,
1023191783Srmacklem	NFSERR_BADXDR,
1024191783Srmacklem	NFSERR_DELAY,
1025191783Srmacklem	NFSERR_DQUOT,
1026191783Srmacklem	NFSERR_EXIST,
1027191783Srmacklem	NFSERR_FHEXPIRED,
1028191783Srmacklem	NFSERR_FILEOPEN,
1029191783Srmacklem	NFSERR_INVAL,
1030191783Srmacklem	NFSERR_IO,
1031191783Srmacklem	NFSERR_MOVED,
1032191783Srmacklem	NFSERR_NAMETOL,
1033191783Srmacklem	NFSERR_NOENT,
1034191783Srmacklem	NFSERR_NOFILEHANDLE,
1035191783Srmacklem	NFSERR_NOSPC,
1036191783Srmacklem	NFSERR_NOTDIR,
1037191783Srmacklem	NFSERR_NOTEMPTY,
1038191783Srmacklem	NFSERR_RESOURCE,
1039191783Srmacklem	NFSERR_ROFS,
1040191783Srmacklem	NFSERR_SERVERFAULT,
1041191783Srmacklem	NFSERR_STALE,
1042191783Srmacklem	NFSERR_WRONGSEC,
1043191783Srmacklem	NFSERR_XDEV,
1044191783Srmacklem	0,
1045191783Srmacklem};
1046191783Srmacklem
1047191783Srmacklemstatic short nfsv4err_renew[] = {
1048191783Srmacklem	NFSERR_SERVERFAULT,
1049191783Srmacklem	NFSERR_ACCES,
1050191783Srmacklem	NFSERR_ADMINREVOKED,
1051191783Srmacklem	NFSERR_BADXDR,
1052191783Srmacklem	NFSERR_CBPATHDOWN,
1053191783Srmacklem	NFSERR_EXPIRED,
1054191783Srmacklem	NFSERR_LEASEMOVED,
1055191783Srmacklem	NFSERR_RESOURCE,
1056191783Srmacklem	NFSERR_SERVERFAULT,
1057191783Srmacklem	NFSERR_STALECLIENTID,
1058191783Srmacklem	0,
1059191783Srmacklem};
1060191783Srmacklem
1061191783Srmacklemstatic short nfsv4err_restorefh[] = {
1062191783Srmacklem	NFSERR_SERVERFAULT,
1063191783Srmacklem	NFSERR_BADHANDLE,
1064191783Srmacklem	NFSERR_FHEXPIRED,
1065191783Srmacklem	NFSERR_MOVED,
1066191783Srmacklem	NFSERR_RESOURCE,
1067191783Srmacklem	NFSERR_RESTOREFH,
1068191783Srmacklem	NFSERR_SERVERFAULT,
1069191783Srmacklem	NFSERR_STALE,
1070191783Srmacklem	NFSERR_WRONGSEC,
1071191783Srmacklem	0,
1072191783Srmacklem};
1073191783Srmacklem
1074191783Srmacklemstatic short nfsv4err_savefh[] = {
1075191783Srmacklem	NFSERR_SERVERFAULT,
1076191783Srmacklem	NFSERR_BADHANDLE,
1077191783Srmacklem	NFSERR_FHEXPIRED,
1078191783Srmacklem	NFSERR_MOVED,
1079191783Srmacklem	NFSERR_NOFILEHANDLE,
1080191783Srmacklem	NFSERR_RESOURCE,
1081191783Srmacklem	NFSERR_SERVERFAULT,
1082191783Srmacklem	NFSERR_STALE,
1083191783Srmacklem	0,
1084191783Srmacklem};
1085191783Srmacklem
1086191783Srmacklemstatic short nfsv4err_secinfo[] = {
1087191783Srmacklem	NFSERR_SERVERFAULT,
1088191783Srmacklem	NFSERR_ACCES,
1089191783Srmacklem	NFSERR_BADCHAR,
1090191783Srmacklem	NFSERR_BADHANDLE,
1091191783Srmacklem	NFSERR_BADNAME,
1092191783Srmacklem	NFSERR_BADXDR,
1093191783Srmacklem	NFSERR_FHEXPIRED,
1094191783Srmacklem	NFSERR_INVAL,
1095191783Srmacklem	NFSERR_MOVED,
1096191783Srmacklem	NFSERR_NAMETOL,
1097191783Srmacklem	NFSERR_NOENT,
1098191783Srmacklem	NFSERR_NOFILEHANDLE,
1099191783Srmacklem	NFSERR_NOTDIR,
1100191783Srmacklem	NFSERR_RESOURCE,
1101191783Srmacklem	NFSERR_SERVERFAULT,
1102191783Srmacklem	NFSERR_STALE,
1103191783Srmacklem	0,
1104191783Srmacklem};
1105191783Srmacklem
1106191783Srmacklemstatic short nfsv4err_setattr[] = {
1107191783Srmacklem	NFSERR_IO,
1108191783Srmacklem	NFSERR_ACCES,
1109191783Srmacklem	NFSERR_ADMINREVOKED,
1110191783Srmacklem	NFSERR_ATTRNOTSUPP,
1111191783Srmacklem	NFSERR_BADCHAR,
1112191783Srmacklem	NFSERR_BADHANDLE,
1113191783Srmacklem	NFSERR_BADOWNER,
1114191783Srmacklem	NFSERR_BADSTATEID,
1115191783Srmacklem	NFSERR_BADXDR,
1116191783Srmacklem	NFSERR_DELAY,
1117191783Srmacklem	NFSERR_DQUOT,
1118191783Srmacklem	NFSERR_EXPIRED,
1119191783Srmacklem	NFSERR_FBIG,
1120191783Srmacklem	NFSERR_FHEXPIRED,
1121191783Srmacklem	NFSERR_GRACE,
1122191783Srmacklem	NFSERR_INVAL,
1123191783Srmacklem	NFSERR_IO,
1124191783Srmacklem	NFSERR_ISDIR,
1125191783Srmacklem	NFSERR_LOCKED,
1126191783Srmacklem	NFSERR_MOVED,
1127191783Srmacklem	NFSERR_NOFILEHANDLE,
1128191783Srmacklem	NFSERR_NOSPC,
1129191783Srmacklem	NFSERR_OLDSTATEID,
1130191783Srmacklem	NFSERR_OPENMODE,
1131191783Srmacklem	NFSERR_PERM,
1132191783Srmacklem	NFSERR_RESOURCE,
1133191783Srmacklem	NFSERR_ROFS,
1134191783Srmacklem	NFSERR_SERVERFAULT,
1135191783Srmacklem	NFSERR_STALE,
1136191783Srmacklem	NFSERR_STALESTATEID,
1137191783Srmacklem	0,
1138191783Srmacklem};
1139191783Srmacklem
1140191783Srmacklemstatic short nfsv4err_setclientid[] = {
1141191783Srmacklem	NFSERR_SERVERFAULT,
1142191783Srmacklem	NFSERR_BADXDR,
1143191783Srmacklem	NFSERR_CLIDINUSE,
1144191783Srmacklem	NFSERR_INVAL,
1145191783Srmacklem	NFSERR_RESOURCE,
1146191783Srmacklem	NFSERR_SERVERFAULT,
1147299223Srmacklem	NFSERR_WRONGSEC,
1148191783Srmacklem	0,
1149191783Srmacklem};
1150191783Srmacklem
1151191783Srmacklemstatic short nfsv4err_setclientidconfirm[] = {
1152191783Srmacklem	NFSERR_SERVERFAULT,
1153191783Srmacklem	NFSERR_BADXDR,
1154191783Srmacklem	NFSERR_CLIDINUSE,
1155191783Srmacklem	NFSERR_RESOURCE,
1156191783Srmacklem	NFSERR_SERVERFAULT,
1157191783Srmacklem	NFSERR_STALECLIENTID,
1158191783Srmacklem	0,
1159191783Srmacklem};
1160191783Srmacklem
1161191783Srmacklemstatic short nfsv4err_verify[] = {
1162191783Srmacklem	NFSERR_SERVERFAULT,
1163191783Srmacklem	NFSERR_ACCES,
1164191783Srmacklem	NFSERR_ATTRNOTSUPP,
1165191783Srmacklem	NFSERR_BADCHAR,
1166191783Srmacklem	NFSERR_BADHANDLE,
1167191783Srmacklem	NFSERR_BADXDR,
1168191783Srmacklem	NFSERR_DELAY,
1169191783Srmacklem	NFSERR_FHEXPIRED,
1170191783Srmacklem	NFSERR_INVAL,
1171191783Srmacklem	NFSERR_MOVED,
1172191783Srmacklem	NFSERR_NOFILEHANDLE,
1173191783Srmacklem	NFSERR_NOTSAME,
1174191783Srmacklem	NFSERR_RESOURCE,
1175191783Srmacklem	NFSERR_SERVERFAULT,
1176191783Srmacklem	NFSERR_STALE,
1177191783Srmacklem	0,
1178191783Srmacklem};
1179191783Srmacklem
1180191783Srmacklemstatic short nfsv4err_write[] = {
1181191783Srmacklem	NFSERR_IO,
1182191783Srmacklem	NFSERR_ACCES,
1183191783Srmacklem	NFSERR_ADMINREVOKED,
1184191783Srmacklem	NFSERR_BADHANDLE,
1185191783Srmacklem	NFSERR_BADSTATEID,
1186191783Srmacklem	NFSERR_BADXDR,
1187191783Srmacklem	NFSERR_DELAY,
1188191783Srmacklem	NFSERR_DQUOT,
1189191783Srmacklem	NFSERR_EXPIRED,
1190191783Srmacklem	NFSERR_FBIG,
1191191783Srmacklem	NFSERR_FHEXPIRED,
1192191783Srmacklem	NFSERR_GRACE,
1193191783Srmacklem	NFSERR_INVAL,
1194191783Srmacklem	NFSERR_IO,
1195191783Srmacklem	NFSERR_ISDIR,
1196191783Srmacklem	NFSERR_LEASEMOVED,
1197191783Srmacklem	NFSERR_LOCKED,
1198191783Srmacklem	NFSERR_MOVED,
1199191783Srmacklem	NFSERR_NOFILEHANDLE,
1200191783Srmacklem	NFSERR_NOSPC,
1201191783Srmacklem	NFSERR_NXIO,
1202191783Srmacklem	NFSERR_OLDSTATEID,
1203191783Srmacklem	NFSERR_OPENMODE,
1204191783Srmacklem	NFSERR_RESOURCE,
1205191783Srmacklem	NFSERR_ROFS,
1206191783Srmacklem	NFSERR_SERVERFAULT,
1207191783Srmacklem	NFSERR_STALE,
1208191783Srmacklem	NFSERR_STALESTATEID,
1209191783Srmacklem	0,
1210191783Srmacklem};
1211191783Srmacklem
1212191783Srmacklemstatic short nfsv4err_releaselockowner[] = {
1213191783Srmacklem	NFSERR_SERVERFAULT,
1214191783Srmacklem	NFSERR_ADMINREVOKED,
1215191783Srmacklem	NFSERR_BADXDR,
1216191783Srmacklem	NFSERR_EXPIRED,
1217191783Srmacklem	NFSERR_LEASEMOVED,
1218191783Srmacklem	NFSERR_LOCKSHELD,
1219191783Srmacklem	NFSERR_RESOURCE,
1220191783Srmacklem	NFSERR_SERVERFAULT,
1221191783Srmacklem	NFSERR_STALECLIENTID,
1222191783Srmacklem	0,
1223191783Srmacklem};
1224191783Srmacklem
1225191783Srmacklemstatic short *nfsrv_v4errmap[] = {
1226191783Srmacklem	nfsv4err_null,
1227191783Srmacklem	nfsv4err_null,
1228191783Srmacklem	nfsv4err_null,
1229191783Srmacklem	nfsv4err_access,
1230191783Srmacklem	nfsv4err_close,
1231191783Srmacklem	nfsv4err_commit,
1232191783Srmacklem	nfsv4err_create,
1233191783Srmacklem	nfsv4err_delegpurge,
1234191783Srmacklem	nfsv4err_delegreturn,
1235191783Srmacklem	nfsv4err_getattr,
1236191783Srmacklem	nfsv4err_getfh,
1237191783Srmacklem	nfsv4err_link,
1238191783Srmacklem	nfsv4err_lock,
1239191783Srmacklem	nfsv4err_lockt,
1240191783Srmacklem	nfsv4err_locku,
1241191783Srmacklem	nfsv4err_lookup,
1242191783Srmacklem	nfsv4err_lookupp,
1243191783Srmacklem	nfsv4err_nverify,
1244191783Srmacklem	nfsv4err_open,
1245191783Srmacklem	nfsv4err_openattr,
1246191783Srmacklem	nfsv4err_openconfirm,
1247191783Srmacklem	nfsv4err_opendowngrade,
1248191783Srmacklem	nfsv4err_putfh,
1249191783Srmacklem	nfsv4err_putpubfh,
1250191783Srmacklem	nfsv4err_putrootfh,
1251191783Srmacklem	nfsv4err_read,
1252191783Srmacklem	nfsv4err_readdir,
1253191783Srmacklem	nfsv4err_readlink,
1254191783Srmacklem	nfsv4err_remove,
1255191783Srmacklem	nfsv4err_rename,
1256191783Srmacklem	nfsv4err_renew,
1257191783Srmacklem	nfsv4err_restorefh,
1258191783Srmacklem	nfsv4err_savefh,
1259191783Srmacklem	nfsv4err_secinfo,
1260191783Srmacklem	nfsv4err_setattr,
1261191783Srmacklem	nfsv4err_setclientid,
1262191783Srmacklem	nfsv4err_setclientidconfirm,
1263191783Srmacklem	nfsv4err_verify,
1264191783Srmacklem	nfsv4err_write,
1265191783Srmacklem	nfsv4err_releaselockowner,
1266191783Srmacklem};
1267191783Srmacklem
1268191783Srmacklem/*
1269191783Srmacklem * A fiddled version of m_adj() that ensures null fill to a long
1270191783Srmacklem * boundary and only trims off the back end
1271191783Srmacklem */
1272191783SrmacklemAPPLESTATIC void
1273191783Srmacklemnfsrv_adj(mbuf_t mp, int len, int nul)
1274191783Srmacklem{
1275191783Srmacklem	mbuf_t m;
1276191783Srmacklem	int count, i;
1277191783Srmacklem	char *cp;
1278191783Srmacklem
1279191783Srmacklem	/*
1280191783Srmacklem	 * Trim from tail.  Scan the mbuf chain,
1281191783Srmacklem	 * calculating its length and finding the last mbuf.
1282191783Srmacklem	 * If the adjustment only affects this mbuf, then just
1283191783Srmacklem	 * adjust and return.  Otherwise, rescan and truncate
1284191783Srmacklem	 * after the remaining size.
1285191783Srmacklem	 */
1286191783Srmacklem	count = 0;
1287191783Srmacklem	m = mp;
1288191783Srmacklem	for (;;) {
1289191783Srmacklem		count += mbuf_len(m);
1290191783Srmacklem		if (mbuf_next(m) == NULL)
1291191783Srmacklem			break;
1292191783Srmacklem		m = mbuf_next(m);
1293191783Srmacklem	}
1294191783Srmacklem	if (mbuf_len(m) > len) {
1295191783Srmacklem		mbuf_setlen(m, mbuf_len(m) - len);
1296191783Srmacklem		if (nul > 0) {
1297191783Srmacklem			cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1298191783Srmacklem			for (i = 0; i < nul; i++)
1299191783Srmacklem				*cp++ = '\0';
1300191783Srmacklem		}
1301191783Srmacklem		return;
1302191783Srmacklem	}
1303191783Srmacklem	count -= len;
1304191783Srmacklem	if (count < 0)
1305191783Srmacklem		count = 0;
1306191783Srmacklem	/*
1307191783Srmacklem	 * Correct length for chain is "count".
1308191783Srmacklem	 * Find the mbuf with last data, adjust its length,
1309191783Srmacklem	 * and toss data from remaining mbufs on chain.
1310191783Srmacklem	 */
1311191783Srmacklem	for (m = mp; m; m = mbuf_next(m)) {
1312191783Srmacklem		if (mbuf_len(m) >= count) {
1313191783Srmacklem			mbuf_setlen(m, count);
1314191783Srmacklem			if (nul > 0) {
1315191783Srmacklem				cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1316191783Srmacklem				for (i = 0; i < nul; i++)
1317191783Srmacklem					*cp++ = '\0';
1318191783Srmacklem			}
1319191783Srmacklem			break;
1320191783Srmacklem		}
1321191783Srmacklem		count -= mbuf_len(m);
1322191783Srmacklem	}
1323191783Srmacklem	for (m = mbuf_next(m); m; m = mbuf_next(m))
1324191783Srmacklem		mbuf_setlen(m, 0);
1325191783Srmacklem}
1326191783Srmacklem
1327191783Srmacklem/*
1328191783Srmacklem * Make these functions instead of macros, so that the kernel text size
1329191783Srmacklem * doesn't get too big...
1330191783Srmacklem */
1331191783SrmacklemAPPLESTATIC void
1332191783Srmacklemnfsrv_wcc(struct nfsrv_descript *nd, int before_ret,
1333191783Srmacklem    struct nfsvattr *before_nvap, int after_ret, struct nfsvattr *after_nvap)
1334191783Srmacklem{
1335191783Srmacklem	u_int32_t *tl;
1336191783Srmacklem
1337191783Srmacklem	if (before_ret) {
1338191783Srmacklem		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1339191783Srmacklem		*tl = newnfs_false;
1340191783Srmacklem	} else {
1341191783Srmacklem		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1342191783Srmacklem		*tl++ = newnfs_true;
1343191783Srmacklem		txdr_hyper(before_nvap->na_size, tl);
1344191783Srmacklem		tl += 2;
1345191783Srmacklem		txdr_nfsv3time(&(before_nvap->na_mtime), tl);
1346191783Srmacklem		tl += 2;
1347191783Srmacklem		txdr_nfsv3time(&(before_nvap->na_ctime), tl);
1348191783Srmacklem	}
1349191783Srmacklem	nfsrv_postopattr(nd, after_ret, after_nvap);
1350191783Srmacklem}
1351191783Srmacklem
1352191783SrmacklemAPPLESTATIC void
1353191783Srmacklemnfsrv_postopattr(struct nfsrv_descript *nd, int after_ret,
1354191783Srmacklem    struct nfsvattr *after_nvap)
1355191783Srmacklem{
1356191783Srmacklem	u_int32_t *tl;
1357191783Srmacklem
1358191783Srmacklem	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1359191783Srmacklem	if (after_ret)
1360191783Srmacklem		*tl = newnfs_false;
1361191783Srmacklem	else {
1362191783Srmacklem		*tl = newnfs_true;
1363191783Srmacklem		nfsrv_fillattr(nd, after_nvap);
1364191783Srmacklem	}
1365191783Srmacklem}
1366191783Srmacklem
1367191783Srmacklem/*
1368191783Srmacklem * Fill in file attributes for V2 and 3. For V4, call a separate
1369191783Srmacklem * routine that sifts through all the attribute bits.
1370191783Srmacklem */
1371191783SrmacklemAPPLESTATIC void
1372191783Srmacklemnfsrv_fillattr(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1373191783Srmacklem{
1374191783Srmacklem	struct nfs_fattr *fp;
1375191783Srmacklem	int fattr_size;
1376191783Srmacklem
1377191783Srmacklem	/*
1378191783Srmacklem	 * Build space for the attribute structure.
1379191783Srmacklem	 */
1380191783Srmacklem	if (nd->nd_flag & ND_NFSV3)
1381191783Srmacklem		fattr_size = NFSX_V3FATTR;
1382191783Srmacklem	else
1383191783Srmacklem		fattr_size = NFSX_V2FATTR;
1384191783Srmacklem	NFSM_BUILD(fp, struct nfs_fattr *, fattr_size);
1385191783Srmacklem
1386191783Srmacklem	/*
1387191783Srmacklem	 * Now just fill it all in.
1388191783Srmacklem	 */
1389191783Srmacklem	fp->fa_nlink = txdr_unsigned(nvap->na_nlink);
1390191783Srmacklem	fp->fa_uid = txdr_unsigned(nvap->na_uid);
1391191783Srmacklem	fp->fa_gid = txdr_unsigned(nvap->na_gid);
1392191783Srmacklem	if (nd->nd_flag & ND_NFSV3) {
1393191783Srmacklem		fp->fa_type = vtonfsv34_type(nvap->na_type);
1394191783Srmacklem		fp->fa_mode = vtonfsv34_mode(nvap->na_mode);
1395191783Srmacklem		txdr_hyper(nvap->na_size, &fp->fa3_size);
1396191783Srmacklem		txdr_hyper(nvap->na_bytes, &fp->fa3_used);
1397191783Srmacklem		fp->fa3_rdev.specdata1 = txdr_unsigned(NFSMAJOR(nvap->na_rdev));
1398191783Srmacklem		fp->fa3_rdev.specdata2 = txdr_unsigned(NFSMINOR(nvap->na_rdev));
1399191783Srmacklem		fp->fa3_fsid.nfsuquad[0] = 0;
1400191783Srmacklem		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(nvap->na_fsid);
1401191783Srmacklem		fp->fa3_fileid.nfsuquad[0] = 0;
1402191783Srmacklem		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(nvap->na_fileid);
1403191783Srmacklem		txdr_nfsv3time(&nvap->na_atime, &fp->fa3_atime);
1404191783Srmacklem		txdr_nfsv3time(&nvap->na_mtime, &fp->fa3_mtime);
1405191783Srmacklem		txdr_nfsv3time(&nvap->na_ctime, &fp->fa3_ctime);
1406191783Srmacklem	} else {
1407191783Srmacklem		fp->fa_type = vtonfsv2_type(nvap->na_type);
1408191783Srmacklem		fp->fa_mode = vtonfsv2_mode(nvap->na_type, nvap->na_mode);
1409191783Srmacklem		fp->fa2_size = txdr_unsigned(nvap->na_size);
1410191783Srmacklem		fp->fa2_blocksize = txdr_unsigned(nvap->na_blocksize);
1411191783Srmacklem		if (nvap->na_type == VFIFO)
1412191783Srmacklem			fp->fa2_rdev = 0xffffffff;
1413191783Srmacklem		else
1414191783Srmacklem			fp->fa2_rdev = txdr_unsigned(nvap->na_rdev);
1415191783Srmacklem		fp->fa2_blocks = txdr_unsigned(nvap->na_bytes / NFS_FABLKSIZE);
1416191783Srmacklem		fp->fa2_fsid = txdr_unsigned(nvap->na_fsid);
1417191783Srmacklem		fp->fa2_fileid = txdr_unsigned(nvap->na_fileid);
1418191783Srmacklem		txdr_nfsv2time(&nvap->na_atime, &fp->fa2_atime);
1419191783Srmacklem		txdr_nfsv2time(&nvap->na_mtime, &fp->fa2_mtime);
1420191783Srmacklem		txdr_nfsv2time(&nvap->na_ctime, &fp->fa2_ctime);
1421191783Srmacklem	}
1422191783Srmacklem}
1423191783Srmacklem
1424191783Srmacklem/*
1425191783Srmacklem * This function gets a file handle out of an mbuf list.
1426191783Srmacklem * It returns 0 for success, EBADRPC otherwise.
1427191783Srmacklem * If sets the third flagp argument to 1 if the file handle is
1428191783Srmacklem * the public file handle.
1429191783Srmacklem * For NFSv4, if the length is incorrect, set nd_repstat == NFSERR_BADHANDLE
1430191783Srmacklem */
1431191783SrmacklemAPPLESTATIC int
1432191783Srmacklemnfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
1433191783Srmacklem{
1434191783Srmacklem	u_int32_t *tl;
1435191783Srmacklem	int error = 0, len, copylen;
1436191783Srmacklem
1437191783Srmacklem	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1438191783Srmacklem		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1439191783Srmacklem		len = fxdr_unsigned(int, *tl);
1440191783Srmacklem		if (len == 0 && nfs_pubfhset && (nd->nd_flag & ND_NFSV3) &&
1441191783Srmacklem		    nd->nd_procnum == NFSPROC_LOOKUP) {
1442191783Srmacklem			nd->nd_flag |= ND_PUBLOOKUP;
1443224086Szack			goto nfsmout;
1444191783Srmacklem		}
1445191783Srmacklem		if (len < NFSRV_MINFH || len > NFSRV_MAXFH) {
1446191783Srmacklem			if (nd->nd_flag & ND_NFSV4) {
1447191783Srmacklem			    if (len > 0 && len <= NFSX_V4FHMAX) {
1448191783Srmacklem				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1449191783Srmacklem				if (error)
1450224086Szack					goto nfsmout;
1451191783Srmacklem				nd->nd_repstat = NFSERR_BADHANDLE;
1452224086Szack				goto nfsmout;
1453191783Srmacklem			    } else {
1454224086Szack				    error = EBADRPC;
1455224086Szack				    goto nfsmout;
1456191783Srmacklem			    }
1457191783Srmacklem			} else {
1458224086Szack				error = EBADRPC;
1459224086Szack				goto nfsmout;
1460191783Srmacklem			}
1461191783Srmacklem		}
1462191783Srmacklem		copylen = len;
1463191783Srmacklem	} else {
1464191783Srmacklem		/*
1465191783Srmacklem		 * For NFSv2, the file handle is always 32 bytes on the
1466191783Srmacklem		 * wire, but this server only cares about the first
1467191783Srmacklem		 * NFSRV_MAXFH bytes.
1468191783Srmacklem		 */
1469191783Srmacklem		len = NFSX_V2FH;
1470191783Srmacklem		copylen = NFSRV_MAXFH;
1471191783Srmacklem	}
1472191783Srmacklem	NFSM_DISSECT(tl, u_int32_t *, len);
1473191783Srmacklem	if ((nd->nd_flag & ND_NFSV2) && nfs_pubfhset &&
1474191783Srmacklem	    nd->nd_procnum == NFSPROC_LOOKUP &&
1475191783Srmacklem	    !NFSBCMP((caddr_t)tl, nfs_v2pubfh, NFSX_V2FH)) {
1476191783Srmacklem		nd->nd_flag |= ND_PUBLOOKUP;
1477224086Szack		goto nfsmout;
1478191783Srmacklem	}
1479191783Srmacklem	NFSBCOPY(tl, (caddr_t)fhp->nfsrvfh_data, copylen);
1480191783Srmacklem	fhp->nfsrvfh_len = copylen;
1481191783Srmacklemnfsmout:
1482224086Szack	NFSEXITCODE2(error, nd);
1483191783Srmacklem	return (error);
1484191783Srmacklem}
1485191783Srmacklem
1486191783Srmacklem/*
1487191783Srmacklem * Map errnos to NFS error numbers. For Version 3 and 4 also filter out error
1488191783Srmacklem * numbers not specified for the associated procedure.
1489191783Srmacklem * NFSPROC_NOOP is a special case, where the high order bits of nd_repstat
1490191783Srmacklem * should be cleared. NFSPROC_NOOP is used to return errors when a valid
1491191783Srmacklem * RPC procedure is not involved.
1492191783Srmacklem * Returns the error number in XDR.
1493191783Srmacklem */
1494191783SrmacklemAPPLESTATIC int
1495191783Srmacklemnfsd_errmap(struct nfsrv_descript *nd)
1496191783Srmacklem{
1497191783Srmacklem	short *defaulterrp, *errp;
1498191783Srmacklem
1499191783Srmacklem	if (!nd->nd_repstat)
1500191783Srmacklem		return (0);
1501191783Srmacklem	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1502191783Srmacklem		if (nd->nd_procnum == NFSPROC_NOOP)
1503191783Srmacklem			return (txdr_unsigned(nd->nd_repstat & 0xffff));
1504191783Srmacklem		if (nd->nd_flag & ND_NFSV3)
1505191783Srmacklem		    errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1506191783Srmacklem		else if (nd->nd_repstat == EBADRPC)
1507191783Srmacklem			return (txdr_unsigned(NFSERR_BADXDR));
1508191783Srmacklem		else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
1509191783Srmacklem			 nd->nd_repstat == NFSERR_OPILLEGAL)
1510191783Srmacklem			return (txdr_unsigned(nd->nd_repstat));
1511269398Srmacklem		else if ((nd->nd_flag & ND_NFSV41) != 0) {
1512269398Srmacklem			if (nd->nd_repstat == EOPNOTSUPP)
1513269398Srmacklem				nd->nd_repstat = NFSERR_NOTSUPP;
1514269398Srmacklem			nd->nd_repstat = nfsrv_isannfserr(nd->nd_repstat);
1515269398Srmacklem			return (txdr_unsigned(nd->nd_repstat));
1516269398Srmacklem		} else
1517191783Srmacklem		    errp = defaulterrp = nfsrv_v4errmap[nd->nd_procnum];
1518191783Srmacklem		while (*++errp)
1519191783Srmacklem			if (*errp == nd->nd_repstat)
1520191783Srmacklem				return (txdr_unsigned(nd->nd_repstat));
1521191783Srmacklem		return (txdr_unsigned(*defaulterrp));
1522191783Srmacklem	}
1523269398Srmacklem	if (nd->nd_repstat <= NFSERR_REMOTE)
1524191783Srmacklem		return (txdr_unsigned(nfsrv_v2errmap[nd->nd_repstat - 1]));
1525191783Srmacklem	return (txdr_unsigned(NFSERR_IO));
1526191783Srmacklem}
1527191783Srmacklem
1528191783Srmacklem/*
1529269398Srmacklem * Check to see if the error is a valid NFS one. If not, replace it with
1530269398Srmacklem * NFSERR_IO.
1531269398Srmacklem */
1532269398Srmacklemstatic u_int32_t
1533269398Srmacklemnfsrv_isannfserr(u_int32_t errval)
1534269398Srmacklem{
1535269398Srmacklem
1536269398Srmacklem	if (errval == NFSERR_OK)
1537269398Srmacklem		return (errval);
1538269398Srmacklem	if (errval >= NFSERR_BADHANDLE && errval <= NFSERR_DELEGREVOKED)
1539269398Srmacklem		return (errval);
1540269398Srmacklem	if (errval > 0 && errval <= NFSERR_REMOTE)
1541269398Srmacklem		return (nfsrv_v2errmap[errval - 1]);
1542269398Srmacklem	return (NFSERR_IO);
1543269398Srmacklem}
1544269398Srmacklem
1545269398Srmacklem/*
1546191783Srmacklem * Check to see if setting a uid/gid is permitted when creating a new
1547191783Srmacklem * file object. (Called when uid and/or gid is specified in the
1548191783Srmacklem * settable attributes for V4.
1549191783Srmacklem */
1550191783SrmacklemAPPLESTATIC int
1551191783Srmacklemnfsrv_checkuidgid(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1552191783Srmacklem{
1553224086Szack	int error = 0;
1554191783Srmacklem
1555191783Srmacklem	/*
1556191783Srmacklem	 * If not setting either uid nor gid, it's OK.
1557191783Srmacklem	 */
1558191783Srmacklem	if (NFSVNO_NOTSETUID(nvap) && NFSVNO_NOTSETGID(nvap))
1559224086Szack		goto out;
1560273877Saraujo	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid == nfsrv_defaultuid &&
1561273877Saraujo           enable_nobodycheck == 1)
1562273877Saraujo	    || (NFSVNO_ISSETGID(nvap) && nvap->na_gid == nfsrv_defaultgid &&
1563273877Saraujo           enable_nogroupcheck == 1)) {
1564224086Szack		error = NFSERR_BADOWNER;
1565224086Szack		goto out;
1566224086Szack	}
1567191783Srmacklem	if (nd->nd_cred->cr_uid == 0)
1568224086Szack		goto out;
1569191783Srmacklem	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid != nd->nd_cred->cr_uid) ||
1570191783Srmacklem	    (NFSVNO_ISSETGID(nvap) && nvap->na_gid != nd->nd_cred->cr_gid &&
1571191783Srmacklem	    !groupmember(nvap->na_gid, nd->nd_cred)))
1572224086Szack		error = NFSERR_PERM;
1573224086Szack
1574224086Szackout:
1575224086Szack	NFSEXITCODE2(error, nd);
1576224086Szack	return (error);
1577191783Srmacklem}
1578191783Srmacklem
1579191783Srmacklem/*
1580191783Srmacklem * and this routine fixes up the settable attributes for V4 if allowed
1581191783Srmacklem * by nfsrv_checkuidgid().
1582191783Srmacklem */
1583191783SrmacklemAPPLESTATIC void
1584191783Srmacklemnfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
1585191783Srmacklem    struct nfsvattr *nvap, NFSACL_T *aclp, NFSPROC_T *p, nfsattrbit_t *attrbitp,
1586191783Srmacklem    struct nfsexstuff *exp)
1587191783Srmacklem{
1588191783Srmacklem	int change = 0;
1589191783Srmacklem	struct nfsvattr nva;
1590191783Srmacklem	uid_t tuid;
1591191783Srmacklem	int error;
1592191783Srmacklem	nfsattrbit_t nattrbits;
1593191783Srmacklem
1594191783Srmacklem	/*
1595191783Srmacklem	 * Maybe this should be done for V2 and 3 but it never has been
1596191783Srmacklem	 * and nobody seems to be upset, so I think it's best not to change
1597191783Srmacklem	 * the V2 and 3 semantics.
1598191783Srmacklem	 */
1599191783Srmacklem	if ((nd->nd_flag & ND_NFSV4) == 0)
1600224086Szack		goto out;
1601191783Srmacklem	NFSVNO_ATTRINIT(&nva);
1602191783Srmacklem	NFSZERO_ATTRBIT(&nattrbits);
1603191783Srmacklem	tuid = nd->nd_cred->cr_uid;
1604191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) &&
1605191783Srmacklem	    NFSVNO_ISSETUID(nvap) &&
1606191783Srmacklem	    nvap->na_uid != nd->nd_cred->cr_uid) {
1607191783Srmacklem		if (nd->nd_cred->cr_uid == 0) {
1608191783Srmacklem			nva.na_uid = nvap->na_uid;
1609191783Srmacklem			change++;
1610191783Srmacklem			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNER);
1611191783Srmacklem		} else {
1612191783Srmacklem			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNER);
1613191783Srmacklem		}
1614191783Srmacklem	}
1615191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESSSET) &&
1616191783Srmacklem	    NFSVNO_ISSETATIME(nvap)) {
1617191783Srmacklem		nva.na_atime = nvap->na_atime;
1618191783Srmacklem		change++;
1619191783Srmacklem		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEACCESSSET);
1620191783Srmacklem	}
1621191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFYSET) &&
1622191783Srmacklem	    NFSVNO_ISSETMTIME(nvap)) {
1623191783Srmacklem		nva.na_mtime = nvap->na_mtime;
1624191783Srmacklem		change++;
1625191783Srmacklem		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEMODIFYSET);
1626191783Srmacklem	}
1627191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) &&
1628191783Srmacklem	    NFSVNO_ISSETGID(nvap)) {
1629191783Srmacklem		if (nvap->na_gid == nd->nd_cred->cr_gid ||
1630191783Srmacklem		    groupmember(nvap->na_gid, nd->nd_cred)) {
1631191783Srmacklem			nd->nd_cred->cr_uid = 0;
1632191783Srmacklem			nva.na_gid = nvap->na_gid;
1633191783Srmacklem			change++;
1634191783Srmacklem			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNERGROUP);
1635191783Srmacklem		} else {
1636191783Srmacklem			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP);
1637191783Srmacklem		}
1638191783Srmacklem	}
1639191783Srmacklem	if (change) {
1640191783Srmacklem		error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
1641191783Srmacklem		if (error) {
1642191783Srmacklem			NFSCLRALL_ATTRBIT(attrbitp, &nattrbits);
1643191783Srmacklem		}
1644191783Srmacklem	}
1645191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) &&
1646191783Srmacklem	    NFSVNO_ISSETSIZE(nvap) && nvap->na_size != (u_quad_t)0) {
1647191783Srmacklem		NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_SIZE);
1648191783Srmacklem	}
1649191783Srmacklem#ifdef NFS4_ACL_EXTATTR_NAME
1650191783Srmacklem	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL) &&
1651191783Srmacklem	    nfsrv_useacl != 0 && aclp != NULL) {
1652191783Srmacklem		if (aclp->acl_cnt > 0) {
1653191783Srmacklem			error = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
1654191783Srmacklem			if (error) {
1655191783Srmacklem				NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1656191783Srmacklem			}
1657191783Srmacklem		}
1658191783Srmacklem	} else
1659191783Srmacklem#endif
1660191783Srmacklem	NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1661191783Srmacklem	nd->nd_cred->cr_uid = tuid;
1662224086Szack
1663224086Szackout:
1664224086Szack	NFSEXITCODE2(0, nd);
1665191783Srmacklem}
1666191783Srmacklem
1667191783Srmacklem/*
1668191783Srmacklem * Translate an ASCII hex digit to it's binary value. Return -1 if the
1669191783Srmacklem * char isn't a hex digit.
1670191783Srmacklem */
1671191783Srmacklemstatic char
1672191783Srmacklemnfsrv_hexdigit(char c, int *err)
1673191783Srmacklem{
1674191783Srmacklem
1675191783Srmacklem	*err = 0;
1676191783Srmacklem	if (c >= '0' && c <= '9')
1677191783Srmacklem		return (c - '0');
1678191783Srmacklem	if (c >= 'a' && c <= 'f')
1679191783Srmacklem		return (c - 'a' + ((char)10));
1680191783Srmacklem	if (c >= 'A' && c <= 'F')
1681191783Srmacklem		return (c - 'A' + ((char)10));
1682191783Srmacklem	/* Not valid ! */
1683191783Srmacklem	*err = 1;
1684191783Srmacklem	return (1);	/* BOGUS */
1685191783Srmacklem}
1686191783Srmacklem
1687191783Srmacklem/*
1688191783Srmacklem * Check to see if NFSERR_MOVED can be returned for this op. Return 1 iff
1689191783Srmacklem * it can be.
1690191783Srmacklem */
1691191783SrmacklemAPPLESTATIC int
1692191783Srmacklemnfsrv_errmoved(int op)
1693191783Srmacklem{
1694191783Srmacklem	short *errp;
1695191783Srmacklem
1696191783Srmacklem	errp = nfsrv_v4errmap[op];
1697191783Srmacklem	while (*errp != 0) {
1698191783Srmacklem		if (*errp == NFSERR_MOVED)
1699191783Srmacklem			return (1);
1700191783Srmacklem		errp++;
1701191783Srmacklem	}
1702191783Srmacklem	return (0);
1703191783Srmacklem}
1704191783Srmacklem
1705191783Srmacklem/*
1706191783Srmacklem * Fill in attributes for a Referral.
1707191783Srmacklem * (Return the number of bytes of XDR created.)
1708191783Srmacklem */
1709191783SrmacklemAPPLESTATIC int
1710191783Srmacklemnfsrv_putreferralattr(struct nfsrv_descript *nd, nfsattrbit_t *retbitp,
1711191783Srmacklem    struct nfsreferral *refp, int getattr, int *reterrp)
1712191783Srmacklem{
1713191783Srmacklem	u_int32_t *tl, *retnump;
1714191783Srmacklem	u_char *cp, *cp2;
1715191783Srmacklem	int prefixnum, retnum = 0, i, len, bitpos, rderrbit = 0, nonrefbit = 0;
1716191783Srmacklem	int fslocationsbit = 0;
1717191783Srmacklem	nfsattrbit_t tmpbits, refbits;
1718191783Srmacklem
1719191783Srmacklem	NFSREFERRAL_ATTRBIT(&refbits);
1720191783Srmacklem	if (getattr)
1721191783Srmacklem		NFSCLRBIT_ATTRBIT(&refbits, NFSATTRBIT_RDATTRERROR);
1722191783Srmacklem	else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_RDATTRERROR))
1723191783Srmacklem		rderrbit = 1;
1724191783Srmacklem	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_FSLOCATIONS))
1725191783Srmacklem		fslocationsbit = 1;
1726191783Srmacklem
1727191783Srmacklem	/*
1728191783Srmacklem	 * Check for the case where unsupported referral attributes are
1729191783Srmacklem	 * requested.
1730191783Srmacklem	 */
1731191783Srmacklem	NFSSET_ATTRBIT(&tmpbits, retbitp);
1732191783Srmacklem	NFSCLRALL_ATTRBIT(&tmpbits, &refbits);
1733191783Srmacklem	if (NFSNONZERO_ATTRBIT(&tmpbits))
1734191783Srmacklem		nonrefbit = 1;
1735191783Srmacklem
1736191783Srmacklem	if (nonrefbit && !fslocationsbit && (getattr || !rderrbit)) {
1737191783Srmacklem		*reterrp = NFSERR_MOVED;
1738191783Srmacklem		return (0);
1739191783Srmacklem	}
1740191783Srmacklem
1741191783Srmacklem	/*
1742191783Srmacklem	 * Now we can fill in the attributes.
1743191783Srmacklem	 */
1744191783Srmacklem	NFSSET_ATTRBIT(&tmpbits, retbitp);
1745191783Srmacklem	NFSCLRNOT_ATTRBIT(&tmpbits, &refbits);
1746191783Srmacklem
1747191783Srmacklem	/*
1748191783Srmacklem	 * Put out the attribute bitmap for the ones being filled in
1749191783Srmacklem	 * and get the field for the number of attributes returned.
1750191783Srmacklem	 */
1751191783Srmacklem	prefixnum = nfsrv_putattrbit(nd, &tmpbits);
1752191783Srmacklem	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1753191783Srmacklem	prefixnum += NFSX_UNSIGNED;
1754191783Srmacklem
1755191783Srmacklem	/*
1756191783Srmacklem	 * Now, loop around filling in the attributes for each bit set.
1757191783Srmacklem	 */
1758191783Srmacklem	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1759191783Srmacklem	    if (NFSISSET_ATTRBIT(&tmpbits, bitpos)) {
1760191783Srmacklem		switch (bitpos) {
1761191783Srmacklem		case NFSATTRBIT_TYPE:
1762191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1763191783Srmacklem			*tl = txdr_unsigned(NFDIR);
1764191783Srmacklem			retnum += NFSX_UNSIGNED;
1765191783Srmacklem			break;
1766191783Srmacklem		case NFSATTRBIT_FSID:
1767191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
1768191783Srmacklem			*tl++ = 0;
1769191783Srmacklem			*tl++ = txdr_unsigned(NFSV4ROOT_FSID0);
1770191783Srmacklem			*tl++ = 0;
1771191783Srmacklem			*tl = txdr_unsigned(NFSV4ROOT_REFERRAL);
1772191783Srmacklem			retnum += NFSX_V4FSID;
1773191783Srmacklem			break;
1774191783Srmacklem		case NFSATTRBIT_RDATTRERROR:
1775191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1776191783Srmacklem			if (nonrefbit)
1777191783Srmacklem				*tl = txdr_unsigned(NFSERR_MOVED);
1778191783Srmacklem			else
1779191783Srmacklem				*tl = 0;
1780191783Srmacklem			retnum += NFSX_UNSIGNED;
1781191783Srmacklem			break;
1782191783Srmacklem		case NFSATTRBIT_FSLOCATIONS:
1783191783Srmacklem			retnum += nfsm_strtom(nd, "/", 1);
1784191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1785191783Srmacklem			*tl = txdr_unsigned(refp->nfr_srvcnt);
1786191783Srmacklem			retnum += NFSX_UNSIGNED;
1787191783Srmacklem			cp = refp->nfr_srvlist;
1788191783Srmacklem			for (i = 0; i < refp->nfr_srvcnt; i++) {
1789191783Srmacklem				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1790191783Srmacklem				*tl = txdr_unsigned(1);
1791191783Srmacklem				retnum += NFSX_UNSIGNED;
1792191783Srmacklem				cp2 = STRCHR(cp, ':');
1793191783Srmacklem				if (cp2 != NULL)
1794191783Srmacklem					len = cp2 - cp;
1795191783Srmacklem				else
1796191783Srmacklem					len = 1;
1797191783Srmacklem				retnum += nfsm_strtom(nd, cp, len);
1798191783Srmacklem				if (cp2 != NULL)
1799191783Srmacklem					cp = cp2 + 1;
1800191783Srmacklem				cp2 = STRCHR(cp, ',');
1801191783Srmacklem				if (cp2 != NULL)
1802191783Srmacklem					len = cp2 - cp;
1803191783Srmacklem				else
1804191783Srmacklem					len = strlen(cp);
1805191783Srmacklem				retnum += nfsm_strtom(nd, cp, len);
1806191783Srmacklem				if (cp2 != NULL)
1807191783Srmacklem					cp = cp2 + 1;
1808191783Srmacklem			}
1809191783Srmacklem			break;
1810191783Srmacklem		case NFSATTRBIT_MOUNTEDONFILEID:
1811191783Srmacklem			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
1812191783Srmacklem			*tl++ = 0;
1813191783Srmacklem			*tl = txdr_unsigned(refp->nfr_dfileno);
1814191783Srmacklem			retnum += NFSX_HYPER;
1815191783Srmacklem			break;
1816191783Srmacklem		default:
1817191783Srmacklem			printf("EEK! Bad V4 refattr bitpos=%d\n", bitpos);
1818191783Srmacklem		};
1819191783Srmacklem	    }
1820191783Srmacklem	}
1821191783Srmacklem	*retnump = txdr_unsigned(retnum);
1822191783Srmacklem	return (retnum + prefixnum);
1823191783Srmacklem}
1824191783Srmacklem
1825191783Srmacklem/*
1826191783Srmacklem * Parse a file name out of a request.
1827191783Srmacklem */
1828191783SrmacklemAPPLESTATIC int
1829191783Srmacklemnfsrv_parsename(struct nfsrv_descript *nd, char *bufp, u_long *hashp,
1830191783Srmacklem    NFSPATHLEN_T *outlenp)
1831191783Srmacklem{
1832191783Srmacklem	char *fromcp, *tocp, val = '\0';
1833191783Srmacklem	mbuf_t md;
1834191783Srmacklem	int i;
1835191783Srmacklem	int rem, len, error = 0, pubtype = 0, outlen = 0, percent = 0;
1836191783Srmacklem	char digit;
1837191783Srmacklem	u_int32_t *tl;
1838191783Srmacklem	u_long hash = 0;
1839191783Srmacklem
1840191783Srmacklem	if (hashp != NULL)
1841191783Srmacklem		*hashp = 0;
1842191783Srmacklem	tocp = bufp;
1843191783Srmacklem	/*
1844191783Srmacklem	 * For V4, check for lookup parent.
1845191783Srmacklem	 * Otherwise, get the component name.
1846191783Srmacklem	 */
1847191783Srmacklem	if ((nd->nd_flag & ND_NFSV4) && nd->nd_procnum == NFSV4OP_LOOKUPP) {
1848191783Srmacklem	    *tocp++ = '.';
1849191783Srmacklem	    hash += ((u_char)'.');
1850191783Srmacklem	    *tocp++ = '.';
1851191783Srmacklem	    hash += ((u_char)'.');
1852191783Srmacklem	    outlen = 2;
1853191783Srmacklem	} else {
1854191783Srmacklem	    /*
1855191783Srmacklem	     * First, get the name length.
1856191783Srmacklem	     */
1857191783Srmacklem	    NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1858191783Srmacklem	    len = fxdr_unsigned(int, *tl);
1859191783Srmacklem	    if (len > NFS_MAXNAMLEN) {
1860191783Srmacklem		nd->nd_repstat = NFSERR_NAMETOL;
1861224086Szack		error = 0;
1862224086Szack		goto nfsmout;
1863191783Srmacklem	    } else if (len <= 0) {
1864191783Srmacklem		nd->nd_repstat = NFSERR_INVAL;
1865224086Szack		error = 0;
1866224086Szack		goto nfsmout;
1867191783Srmacklem	    }
1868191783Srmacklem
1869191783Srmacklem	    /*
1870191783Srmacklem	     * Now, copy the component name into the buffer.
1871191783Srmacklem	     */
1872191783Srmacklem	    fromcp = nd->nd_dpos;
1873191783Srmacklem	    md = nd->nd_md;
1874191783Srmacklem	    rem = NFSMTOD(md, caddr_t) + mbuf_len(md) - fromcp;
1875191783Srmacklem	    for (i = 0; i < len; i++) {
1876191783Srmacklem		while (rem == 0) {
1877191783Srmacklem			md = mbuf_next(md);
1878224086Szack			if (md == NULL) {
1879224086Szack				error = EBADRPC;
1880224086Szack				goto nfsmout;
1881224086Szack			}
1882191783Srmacklem			fromcp = NFSMTOD(md, caddr_t);
1883191783Srmacklem			rem = mbuf_len(md);
1884191783Srmacklem		}
1885191783Srmacklem		if (*fromcp == '\0') {
1886191783Srmacklem			nd->nd_repstat = EACCES;
1887224086Szack			error = 0;
1888224086Szack			goto nfsmout;
1889191783Srmacklem		}
1890191783Srmacklem		/*
1891191783Srmacklem		 * For lookups on the public filehandle, do some special
1892191783Srmacklem		 * processing on the name. (The public file handle is the
1893191783Srmacklem		 * root of the public file system for this server.)
1894191783Srmacklem		 */
1895191783Srmacklem		if (nd->nd_flag & ND_PUBLOOKUP) {
1896191783Srmacklem			/*
1897191783Srmacklem			 * If the first char is ASCII, it is a canonical
1898191783Srmacklem			 * path, otherwise it is a native path. (RFC2054
1899191783Srmacklem			 * doesn't actually state what it is if the first
1900191783Srmacklem			 * char isn't ASCII or 0x80, so I assume native.)
1901191783Srmacklem			 * pubtype == 1 -> native path
1902191783Srmacklem			 * pubtype == 2 -> canonical path
1903191783Srmacklem			 */
1904191783Srmacklem			if (i == 0) {
1905191783Srmacklem				if (*fromcp & 0x80) {
1906191783Srmacklem					/*
1907191783Srmacklem					 * Since RFC2054 doesn't indicate
1908191783Srmacklem					 * that a native path of just 0x80
1909191783Srmacklem					 * isn't allowed, I'll replace the
1910191783Srmacklem					 * 0x80 with '/' instead of just
1911191783Srmacklem					 * throwing it away.
1912191783Srmacklem					 */
1913191783Srmacklem					*fromcp = '/';
1914191783Srmacklem					pubtype = 1;
1915191783Srmacklem				} else {
1916191783Srmacklem					pubtype = 2;
1917191783Srmacklem				}
1918191783Srmacklem			}
1919191783Srmacklem			/*
1920191783Srmacklem			 * '/' only allowed in a native path
1921191783Srmacklem			 */
1922191783Srmacklem			if (*fromcp == '/' && pubtype != 1) {
1923191783Srmacklem				nd->nd_repstat = EACCES;
1924224086Szack				error = 0;
1925224086Szack				goto nfsmout;
1926191783Srmacklem			}
1927191783Srmacklem
1928191783Srmacklem			/*
1929191783Srmacklem			 * For the special case of 2 hex digits after a
1930191783Srmacklem			 * '%' in an absolute path, calculate the value.
1931191783Srmacklem			 * percent == 1 -> indicates "get first hex digit"
1932191783Srmacklem			 * percent == 2 -> indicates "get second hex digit"
1933191783Srmacklem			 */
1934191783Srmacklem			if (percent > 0) {
1935191783Srmacklem				digit = nfsrv_hexdigit(*fromcp, &error);
1936191783Srmacklem				if (error) {
1937191783Srmacklem					nd->nd_repstat = EACCES;
1938224086Szack					error = 0;
1939224086Szack					goto nfsmout;
1940191783Srmacklem				}
1941191783Srmacklem				if (percent == 1) {
1942191783Srmacklem					val = (digit << 4);
1943191783Srmacklem					percent = 2;
1944191783Srmacklem				} else {
1945191783Srmacklem					val += digit;
1946191783Srmacklem					percent = 0;
1947191783Srmacklem					*tocp++ = val;
1948191783Srmacklem					hash += ((u_char)val);
1949191783Srmacklem					outlen++;
1950191783Srmacklem				}
1951191783Srmacklem			} else {
1952191783Srmacklem				if (*fromcp == '%' && pubtype == 2) {
1953191783Srmacklem					/*
1954191783Srmacklem					 * Must be followed by 2 hex digits
1955191783Srmacklem					 */
1956191783Srmacklem					if ((len - i) < 3) {
1957191783Srmacklem						nd->nd_repstat = EACCES;
1958224086Szack						error = 0;
1959224086Szack						goto nfsmout;
1960191783Srmacklem					}
1961191783Srmacklem					percent = 1;
1962191783Srmacklem				} else {
1963191783Srmacklem					*tocp++ = *fromcp;
1964191783Srmacklem					hash += ((u_char)*fromcp);
1965191783Srmacklem					outlen++;
1966191783Srmacklem				}
1967191783Srmacklem			}
1968191783Srmacklem		} else {
1969191783Srmacklem			/*
1970191783Srmacklem			 * Normal, non lookup on public, name.
1971191783Srmacklem			 */
1972191783Srmacklem			if (*fromcp == '/') {
1973191783Srmacklem				if (nd->nd_flag & ND_NFSV4)
1974191783Srmacklem					nd->nd_repstat = NFSERR_BADNAME;
1975191783Srmacklem				else
1976191783Srmacklem					nd->nd_repstat = EACCES;
1977224086Szack				error = 0;
1978224086Szack				goto nfsmout;
1979191783Srmacklem			}
1980191783Srmacklem			hash += ((u_char)*fromcp);
1981191783Srmacklem			*tocp++ = *fromcp;
1982191783Srmacklem			outlen++;
1983191783Srmacklem		}
1984191783Srmacklem		fromcp++;
1985191783Srmacklem		rem--;
1986191783Srmacklem	    }
1987191783Srmacklem	    nd->nd_md = md;
1988191783Srmacklem	    nd->nd_dpos = fromcp;
1989191783Srmacklem	    i = NFSM_RNDUP(len) - len;
1990191783Srmacklem	    if (i > 0) {
1991191783Srmacklem		if (rem >= i) {
1992191783Srmacklem			nd->nd_dpos += i;
1993191783Srmacklem		} else {
1994191783Srmacklem			error = nfsm_advance(nd, i, rem);
1995191783Srmacklem			if (error)
1996224086Szack				goto nfsmout;
1997191783Srmacklem		}
1998191783Srmacklem	    }
1999191783Srmacklem
2000191783Srmacklem	    /*
2001191783Srmacklem	     * For v4, don't allow lookups of '.' or '..' and
2002191783Srmacklem	     * also check for non-utf8 strings.
2003191783Srmacklem	     */
2004191783Srmacklem	    if (nd->nd_flag & ND_NFSV4) {
2005191783Srmacklem		if ((outlen == 1 && bufp[0] == '.') ||
2006191783Srmacklem		    (outlen == 2 && bufp[0] == '.' &&
2007191783Srmacklem		     bufp[1] == '.')) {
2008191783Srmacklem		    nd->nd_repstat = NFSERR_BADNAME;
2009224086Szack		    error = 0;
2010224086Szack		    goto nfsmout;
2011191783Srmacklem		}
2012228260Srmacklem		if (disable_checkutf8 == 0 &&
2013228260Srmacklem		    nfsrv_checkutf8((u_int8_t *)bufp, outlen)) {
2014191783Srmacklem		    nd->nd_repstat = NFSERR_INVAL;
2015224086Szack		    error = 0;
2016224086Szack		    goto nfsmout;
2017191783Srmacklem		}
2018191783Srmacklem	    }
2019191783Srmacklem	}
2020191783Srmacklem	*tocp = '\0';
2021191783Srmacklem	*outlenp = (size_t)outlen;
2022191783Srmacklem	if (hashp != NULL)
2023191783Srmacklem		*hashp = hash;
2024191783Srmacklemnfsmout:
2025224086Szack	NFSEXITCODE2(error, nd);
2026191783Srmacklem	return (error);
2027191783Srmacklem}
2028191783Srmacklem
2029191783Srmacklemvoid
2030191783Srmacklemnfsd_init(void)
2031191783Srmacklem{
2032191783Srmacklem	int i;
2033191783Srmacklem	static int inited = 0;
2034191783Srmacklem
2035191783Srmacklem	if (inited)
2036191783Srmacklem		return;
2037191783Srmacklem	inited = 1;
2038191783Srmacklem
2039191783Srmacklem	/*
2040191783Srmacklem	 * Initialize client queues. Don't free/reinitialize
2041191783Srmacklem	 * them when nfsds are restarted.
2042191783Srmacklem	 */
2043284216Srmacklem	nfsclienthash = malloc(sizeof(struct nfsclienthashhead) *
2044284216Srmacklem	    nfsrv_clienthashsize, M_NFSDCLIENT, M_WAITOK | M_ZERO);
2045284216Srmacklem	for (i = 0; i < nfsrv_clienthashsize; i++)
2046191783Srmacklem		LIST_INIT(&nfsclienthash[i]);
2047284216Srmacklem	nfslockhash = malloc(sizeof(struct nfslockhashhead) *
2048284216Srmacklem	    nfsrv_lockhashsize, M_NFSDLOCKFILE, M_WAITOK | M_ZERO);
2049284216Srmacklem	for (i = 0; i < nfsrv_lockhashsize; i++)
2050191783Srmacklem		LIST_INIT(&nfslockhash[i]);
2051284216Srmacklem	nfssessionhash = malloc(sizeof(struct nfssessionhash) *
2052284216Srmacklem	    nfsrv_sessionhashsize, M_NFSDSESSION, M_WAITOK | M_ZERO);
2053284216Srmacklem	for (i = 0; i < nfsrv_sessionhashsize; i++) {
2054284216Srmacklem		mtx_init(&nfssessionhash[i].mtx, "nfssm", NULL, MTX_DEF);
2055269398Srmacklem		LIST_INIT(&nfssessionhash[i].list);
2056284216Srmacklem	}
2057191783Srmacklem
2058191783Srmacklem	/* and the v2 pubfh should be all zeros */
2059191783Srmacklem	NFSBZERO(nfs_v2pubfh, NFSX_V2FH);
2060191783Srmacklem}
2061191783Srmacklem
2062192121Srmacklem/*
2063192121Srmacklem * Check the v4 root exports.
2064192121Srmacklem * Return 0 if ok, 1 otherwise.
2065192121Srmacklem */
2066192121Srmacklemint
2067192121Srmacklemnfsd_checkrootexp(struct nfsrv_descript *nd)
2068192121Srmacklem{
2069192121Srmacklem
2070192121Srmacklem	if ((nd->nd_flag & (ND_GSS | ND_EXAUTHSYS)) == ND_EXAUTHSYS)
2071192121Srmacklem		return (0);
2072192121Srmacklem	if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) ==
2073192121Srmacklem	    (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY))
2074192121Srmacklem		return (0);
2075192121Srmacklem	if ((nd->nd_flag & (ND_GSSPRIVACY | ND_EXGSSPRIVACY)) ==
2076192121Srmacklem	    (ND_GSSPRIVACY | ND_EXGSSPRIVACY))
2077192121Srmacklem		return (0);
2078192121Srmacklem	if ((nd->nd_flag & (ND_GSS | ND_GSSINTEGRITY | ND_GSSPRIVACY |
2079192121Srmacklem	     ND_EXGSS)) == (ND_GSS | ND_EXGSS))
2080192121Srmacklem		return (0);
2081192121Srmacklem	return (1);
2082192121Srmacklem}
2083192121Srmacklem
2084269398Srmacklem/*
2085269398Srmacklem * Parse the first part of an NFSv4 compound to find out what the minor
2086269398Srmacklem * version# is.
2087269398Srmacklem */
2088269398Srmacklemvoid
2089269398Srmacklemnfsd_getminorvers(struct nfsrv_descript *nd, u_char *tag, u_char **tagstrp,
2090269398Srmacklem    int *taglenp, u_int32_t *minversp)
2091269398Srmacklem{
2092269398Srmacklem	uint32_t *tl;
2093269398Srmacklem	int error = 0, taglen = -1;
2094269398Srmacklem	u_char *tagstr = NULL;
2095269398Srmacklem
2096269398Srmacklem	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2097269398Srmacklem	taglen = fxdr_unsigned(int, *tl);
2098269398Srmacklem	if (taglen < 0 || taglen > NFSV4_OPAQUELIMIT) {
2099269398Srmacklem		error = EBADRPC;
2100269398Srmacklem		goto nfsmout;
2101269398Srmacklem	}
2102269398Srmacklem	if (taglen <= NFSV4_SMALLSTR)
2103269398Srmacklem		tagstr = tag;
2104269398Srmacklem	else
2105269398Srmacklem		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
2106269398Srmacklem	error = nfsrv_mtostr(nd, tagstr, taglen);
2107269398Srmacklem	if (error != 0)
2108269398Srmacklem		goto nfsmout;
2109269398Srmacklem	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2110269398Srmacklem	*minversp = fxdr_unsigned(u_int32_t, *tl);
2111269398Srmacklem	*tagstrp = tagstr;
2112269398Srmacklem	if (*minversp == NFSV41_MINORVERSION)
2113269398Srmacklem		nd->nd_flag |= ND_NFSV41;
2114269398Srmacklemnfsmout:
2115269398Srmacklem	if (error != 0) {
2116269398Srmacklem		if (tagstr != NULL && taglen > NFSV4_SMALLSTR)
2117269398Srmacklem			free(tagstr, M_TEMP);
2118269398Srmacklem		taglen = -1;
2119269398Srmacklem	}
2120269398Srmacklem	*taglenp = taglen;
2121269398Srmacklem}
2122269398Srmacklem
2123