nfs_nfsdsubs.c revision 273877
1/*-
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: stable/10/sys/fs/nfsserver/nfs_nfsdsubs.c 273877 2014-10-31 04:01:10Z araujo $");
36
37#ifndef APPLEKEXT
38/*
39 * These functions support the macros and help fiddle mbuf chains for
40 * the nfs op functions. They do things like create the rpc header and
41 * copy data between mbuf chains and uio lists.
42 */
43#include <fs/nfs/nfsport.h>
44
45extern u_int32_t newnfs_true, newnfs_false;
46extern int nfs_pubfhset;
47extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
48extern struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE];
49extern struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE];
50extern int nfsrv_useacl;
51extern uid_t nfsrv_defaultuid;
52extern gid_t nfsrv_defaultgid;
53
54char nfs_v2pubfh[NFSX_V2FH];
55static nfstype newnfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
56    NFNON, NFCHR, NFNON };
57extern nfstype nfsv34_type[9];
58#endif	/* !APPLEKEXT */
59
60static u_int32_t nfsrv_isannfserr(u_int32_t);
61
62SYSCTL_DECL(_vfs_nfsd);
63
64static int	disable_checkutf8 = 0;
65SYSCTL_INT(_vfs_nfsd, OID_AUTO, disable_checkutf8, CTLFLAG_RW,
66    &disable_checkutf8, 0,
67    "Disable the NFSv4 check for a UTF8 compliant name");
68
69static int    enable_nobodycheck = 1;
70SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_nobodycheck, CTLFLAG_RW,
71    &enable_nobodycheck, 0,
72    "Enable the NFSv4 check when setting user nobody as owner");
73
74static int    enable_nogroupcheck = 1;
75SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_nogroupcheck, CTLFLAG_RW,
76    &enable_nogroupcheck, 0,
77    "Enable the NFSv4 check when setting group nogroup as owner");
78
79static char nfsrv_hexdigit(char, int *);
80
81/*
82 * Maps errno values to nfs error numbers.
83 * Use NFSERR_IO as the catch all for ones not specifically defined in
84 * RFC 1094. (It now includes the errors added for NFSv3.)
85 */
86static u_char nfsrv_v2errmap[NFSERR_REMOTE] = {
87  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
88  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
89  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
90  NFSERR_IO,	NFSERR_EXIST,	NFSERR_XDEV,	NFSERR_NODEV,	NFSERR_NOTDIR,
91  NFSERR_ISDIR,	NFSERR_INVAL,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
92  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
93  NFSERR_MLINK,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
94  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
95  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
96  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
97  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
98  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
99  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
100  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
101  NFSERR_REMOTE,
102};
103
104/*
105 * Maps errno values to nfs error numbers.
106 * Although it is not obvious whether or not NFS clients really care if
107 * a returned error value is in the specified list for the procedure, the
108 * safest thing to do is filter them appropriately. For Version 2, the
109 * X/Open XNFS document is the only specification that defines error values
110 * for each RPC (The RFC simply lists all possible error values for all RPCs),
111 * so I have decided to not do this for Version 2.
112 * The first entry is the default error return and the rest are the valid
113 * errors for that RPC in increasing numeric order.
114 */
115static short nfsv3err_null[] = {
116	0,
117	0,
118};
119
120static short nfsv3err_getattr[] = {
121	NFSERR_IO,
122	NFSERR_IO,
123	NFSERR_STALE,
124	NFSERR_BADHANDLE,
125	NFSERR_SERVERFAULT,
126	NFSERR_DELAY,
127	0,
128};
129
130static short nfsv3err_setattr[] = {
131	NFSERR_IO,
132	NFSERR_ACCES,
133	NFSERR_PERM,
134	NFSERR_IO,
135	NFSERR_INVAL,
136	NFSERR_NOSPC,
137	NFSERR_ROFS,
138	NFSERR_DQUOT,
139	NFSERR_STALE,
140	NFSERR_BADHANDLE,
141	NFSERR_NOT_SYNC,
142	NFSERR_SERVERFAULT,
143	NFSERR_DELAY,
144	0,
145};
146
147static short nfsv3err_lookup[] = {
148	NFSERR_IO,
149	NFSERR_NOENT,
150	NFSERR_ACCES,
151	NFSERR_NAMETOL,
152	NFSERR_IO,
153	NFSERR_NOTDIR,
154	NFSERR_STALE,
155	NFSERR_BADHANDLE,
156	NFSERR_SERVERFAULT,
157	NFSERR_DELAY,
158	0,
159};
160
161static short nfsv3err_access[] = {
162	NFSERR_IO,
163	NFSERR_IO,
164	NFSERR_STALE,
165	NFSERR_BADHANDLE,
166	NFSERR_SERVERFAULT,
167	NFSERR_DELAY,
168	0,
169};
170
171static short nfsv3err_readlink[] = {
172	NFSERR_IO,
173	NFSERR_IO,
174	NFSERR_ACCES,
175	NFSERR_INVAL,
176	NFSERR_STALE,
177	NFSERR_BADHANDLE,
178	NFSERR_NOTSUPP,
179	NFSERR_SERVERFAULT,
180	NFSERR_DELAY,
181	0,
182};
183
184static short nfsv3err_read[] = {
185	NFSERR_IO,
186	NFSERR_IO,
187	NFSERR_NXIO,
188	NFSERR_ACCES,
189	NFSERR_INVAL,
190	NFSERR_STALE,
191	NFSERR_BADHANDLE,
192	NFSERR_SERVERFAULT,
193	NFSERR_DELAY,
194	0,
195};
196
197static short nfsv3err_write[] = {
198	NFSERR_IO,
199	NFSERR_IO,
200	NFSERR_ACCES,
201	NFSERR_NOSPC,
202	NFSERR_INVAL,
203	NFSERR_FBIG,
204	NFSERR_ROFS,
205	NFSERR_DQUOT,
206	NFSERR_STALE,
207	NFSERR_BADHANDLE,
208	NFSERR_SERVERFAULT,
209	NFSERR_DELAY,
210	0,
211};
212
213static short nfsv3err_create[] = {
214	NFSERR_IO,
215	NFSERR_EXIST,
216	NFSERR_NAMETOL,
217	NFSERR_ACCES,
218	NFSERR_IO,
219	NFSERR_NOTDIR,
220	NFSERR_NOSPC,
221	NFSERR_ROFS,
222	NFSERR_DQUOT,
223	NFSERR_STALE,
224	NFSERR_BADHANDLE,
225	NFSERR_NOTSUPP,
226	NFSERR_SERVERFAULT,
227	NFSERR_DELAY,
228	0,
229};
230
231static short nfsv3err_mkdir[] = {
232	NFSERR_IO,
233	NFSERR_EXIST,
234	NFSERR_ACCES,
235	NFSERR_NAMETOL,
236	NFSERR_IO,
237	NFSERR_NOTDIR,
238	NFSERR_NOSPC,
239	NFSERR_ROFS,
240	NFSERR_DQUOT,
241	NFSERR_STALE,
242	NFSERR_BADHANDLE,
243	NFSERR_NOTSUPP,
244	NFSERR_SERVERFAULT,
245	NFSERR_DELAY,
246	0,
247};
248
249static short nfsv3err_symlink[] = {
250	NFSERR_IO,
251	NFSERR_ACCES,
252	NFSERR_EXIST,
253	NFSERR_NAMETOL,
254	NFSERR_NOSPC,
255	NFSERR_IO,
256	NFSERR_NOTDIR,
257	NFSERR_ROFS,
258	NFSERR_DQUOT,
259	NFSERR_STALE,
260	NFSERR_BADHANDLE,
261	NFSERR_NOTSUPP,
262	NFSERR_SERVERFAULT,
263	NFSERR_DELAY,
264	0,
265};
266
267static short nfsv3err_mknod[] = {
268	NFSERR_IO,
269	NFSERR_ACCES,
270	NFSERR_EXIST,
271	NFSERR_NAMETOL,
272	NFSERR_NOSPC,
273	NFSERR_IO,
274	NFSERR_NOTDIR,
275	NFSERR_ROFS,
276	NFSERR_DQUOT,
277	NFSERR_STALE,
278	NFSERR_BADHANDLE,
279	NFSERR_NOTSUPP,
280	NFSERR_SERVERFAULT,
281	NFSERR_DELAY,
282	NFSERR_BADTYPE,
283	0,
284};
285
286static short nfsv3err_remove[] = {
287	NFSERR_IO,
288	NFSERR_NOENT,
289	NFSERR_ACCES,
290	NFSERR_NAMETOL,
291	NFSERR_IO,
292	NFSERR_NOTDIR,
293	NFSERR_ROFS,
294	NFSERR_STALE,
295	NFSERR_BADHANDLE,
296	NFSERR_SERVERFAULT,
297	NFSERR_DELAY,
298	0,
299};
300
301static short nfsv3err_rmdir[] = {
302	NFSERR_IO,
303	NFSERR_NOENT,
304	NFSERR_ACCES,
305	NFSERR_NOTDIR,
306	NFSERR_NAMETOL,
307	NFSERR_IO,
308	NFSERR_EXIST,
309	NFSERR_INVAL,
310	NFSERR_ROFS,
311	NFSERR_NOTEMPTY,
312	NFSERR_STALE,
313	NFSERR_BADHANDLE,
314	NFSERR_NOTSUPP,
315	NFSERR_SERVERFAULT,
316	NFSERR_DELAY,
317	0,
318};
319
320static short nfsv3err_rename[] = {
321	NFSERR_IO,
322	NFSERR_NOENT,
323	NFSERR_ACCES,
324	NFSERR_EXIST,
325	NFSERR_NAMETOL,
326	NFSERR_XDEV,
327	NFSERR_IO,
328	NFSERR_NOTDIR,
329	NFSERR_ISDIR,
330	NFSERR_INVAL,
331	NFSERR_NOSPC,
332	NFSERR_ROFS,
333	NFSERR_MLINK,
334	NFSERR_NOTEMPTY,
335	NFSERR_DQUOT,
336	NFSERR_STALE,
337	NFSERR_BADHANDLE,
338	NFSERR_NOTSUPP,
339	NFSERR_SERVERFAULT,
340	NFSERR_DELAY,
341	0,
342};
343
344static short nfsv3err_link[] = {
345	NFSERR_IO,
346	NFSERR_ACCES,
347	NFSERR_EXIST,
348	NFSERR_NAMETOL,
349	NFSERR_IO,
350	NFSERR_XDEV,
351	NFSERR_NOTDIR,
352	NFSERR_INVAL,
353	NFSERR_NOSPC,
354	NFSERR_ROFS,
355	NFSERR_MLINK,
356	NFSERR_DQUOT,
357	NFSERR_STALE,
358	NFSERR_BADHANDLE,
359	NFSERR_NOTSUPP,
360	NFSERR_SERVERFAULT,
361	NFSERR_DELAY,
362	0,
363};
364
365static short nfsv3err_readdir[] = {
366	NFSERR_IO,
367	NFSERR_ACCES,
368	NFSERR_NOTDIR,
369	NFSERR_IO,
370	NFSERR_STALE,
371	NFSERR_BADHANDLE,
372	NFSERR_BAD_COOKIE,
373	NFSERR_TOOSMALL,
374	NFSERR_SERVERFAULT,
375	NFSERR_DELAY,
376	0,
377};
378
379static short nfsv3err_readdirplus[] = {
380	NFSERR_IO,
381	NFSERR_ACCES,
382	NFSERR_NOTDIR,
383	NFSERR_IO,
384	NFSERR_STALE,
385	NFSERR_BADHANDLE,
386	NFSERR_BAD_COOKIE,
387	NFSERR_NOTSUPP,
388	NFSERR_TOOSMALL,
389	NFSERR_SERVERFAULT,
390	NFSERR_DELAY,
391	0,
392};
393
394static short nfsv3err_fsstat[] = {
395	NFSERR_IO,
396	NFSERR_IO,
397	NFSERR_STALE,
398	NFSERR_BADHANDLE,
399	NFSERR_SERVERFAULT,
400	NFSERR_DELAY,
401	0,
402};
403
404static short nfsv3err_fsinfo[] = {
405	NFSERR_STALE,
406	NFSERR_STALE,
407	NFSERR_BADHANDLE,
408	NFSERR_SERVERFAULT,
409	NFSERR_DELAY,
410	0,
411};
412
413static short nfsv3err_pathconf[] = {
414	NFSERR_STALE,
415	NFSERR_STALE,
416	NFSERR_BADHANDLE,
417	NFSERR_SERVERFAULT,
418	NFSERR_DELAY,
419	0,
420};
421
422static short nfsv3err_commit[] = {
423	NFSERR_IO,
424	NFSERR_IO,
425	NFSERR_STALE,
426	NFSERR_BADHANDLE,
427	NFSERR_SERVERFAULT,
428	NFSERR_DELAY,
429	0,
430};
431
432static short *nfsrv_v3errmap[] = {
433	nfsv3err_null,
434	nfsv3err_getattr,
435	nfsv3err_setattr,
436	nfsv3err_lookup,
437	nfsv3err_access,
438	nfsv3err_readlink,
439	nfsv3err_read,
440	nfsv3err_write,
441	nfsv3err_create,
442	nfsv3err_mkdir,
443	nfsv3err_symlink,
444	nfsv3err_mknod,
445	nfsv3err_remove,
446	nfsv3err_rmdir,
447	nfsv3err_rename,
448	nfsv3err_link,
449	nfsv3err_readdir,
450	nfsv3err_readdirplus,
451	nfsv3err_fsstat,
452	nfsv3err_fsinfo,
453	nfsv3err_pathconf,
454	nfsv3err_commit,
455};
456
457/*
458 * And the same for V4.
459 */
460static short nfsv4err_null[] = {
461	0,
462	0,
463};
464
465static short nfsv4err_access[] = {
466	NFSERR_IO,
467	NFSERR_ACCES,
468	NFSERR_BADHANDLE,
469	NFSERR_BADXDR,
470	NFSERR_DELAY,
471	NFSERR_FHEXPIRED,
472	NFSERR_INVAL,
473	NFSERR_IO,
474	NFSERR_MOVED,
475	NFSERR_NOFILEHANDLE,
476	NFSERR_RESOURCE,
477	NFSERR_SERVERFAULT,
478	NFSERR_STALE,
479	0,
480};
481
482static short nfsv4err_close[] = {
483	NFSERR_EXPIRED,
484	NFSERR_ADMINREVOKED,
485	NFSERR_BADHANDLE,
486	NFSERR_BADSEQID,
487	NFSERR_BADSTATEID,
488	NFSERR_BADXDR,
489	NFSERR_DELAY,
490	NFSERR_EXPIRED,
491	NFSERR_FHEXPIRED,
492	NFSERR_INVAL,
493	NFSERR_ISDIR,
494	NFSERR_LEASEMOVED,
495	NFSERR_LOCKSHELD,
496	NFSERR_MOVED,
497	NFSERR_NOFILEHANDLE,
498	NFSERR_OLDSTATEID,
499	NFSERR_RESOURCE,
500	NFSERR_SERVERFAULT,
501	NFSERR_STALE,
502	NFSERR_STALESTATEID,
503	0,
504};
505
506static short nfsv4err_commit[] = {
507	NFSERR_IO,
508	NFSERR_ACCES,
509	NFSERR_BADHANDLE,
510	NFSERR_BADXDR,
511	NFSERR_FHEXPIRED,
512	NFSERR_INVAL,
513	NFSERR_IO,
514	NFSERR_ISDIR,
515	NFSERR_MOVED,
516	NFSERR_NOFILEHANDLE,
517	NFSERR_RESOURCE,
518	NFSERR_ROFS,
519	NFSERR_SERVERFAULT,
520	NFSERR_STALE,
521	0,
522};
523
524static short nfsv4err_create[] = {
525	NFSERR_IO,
526	NFSERR_ACCES,
527	NFSERR_ATTRNOTSUPP,
528	NFSERR_BADCHAR,
529	NFSERR_BADHANDLE,
530	NFSERR_BADNAME,
531	NFSERR_BADOWNER,
532	NFSERR_BADTYPE,
533	NFSERR_BADXDR,
534	NFSERR_DELAY,
535	NFSERR_DQUOT,
536	NFSERR_EXIST,
537	NFSERR_FHEXPIRED,
538	NFSERR_INVAL,
539	NFSERR_IO,
540	NFSERR_MOVED,
541	NFSERR_NAMETOL,
542	NFSERR_NOFILEHANDLE,
543	NFSERR_NOSPC,
544	NFSERR_NOTDIR,
545	NFSERR_PERM,
546	NFSERR_RESOURCE,
547	NFSERR_ROFS,
548	NFSERR_SERVERFAULT,
549	NFSERR_STALE,
550	0,
551};
552
553static short nfsv4err_delegpurge[] = {
554	NFSERR_SERVERFAULT,
555	NFSERR_BADXDR,
556	NFSERR_NOTSUPP,
557	NFSERR_LEASEMOVED,
558	NFSERR_MOVED,
559	NFSERR_RESOURCE,
560	NFSERR_SERVERFAULT,
561	NFSERR_STALECLIENTID,
562	0,
563};
564
565static short nfsv4err_delegreturn[] = {
566	NFSERR_SERVERFAULT,
567	NFSERR_ADMINREVOKED,
568	NFSERR_BADSTATEID,
569	NFSERR_BADXDR,
570	NFSERR_EXPIRED,
571	NFSERR_INVAL,
572	NFSERR_LEASEMOVED,
573	NFSERR_MOVED,
574	NFSERR_NOFILEHANDLE,
575	NFSERR_NOTSUPP,
576	NFSERR_OLDSTATEID,
577	NFSERR_RESOURCE,
578	NFSERR_SERVERFAULT,
579	NFSERR_STALE,
580	NFSERR_STALESTATEID,
581	0,
582};
583
584static short nfsv4err_getattr[] = {
585	NFSERR_IO,
586	NFSERR_ACCES,
587	NFSERR_BADHANDLE,
588	NFSERR_BADXDR,
589	NFSERR_DELAY,
590	NFSERR_FHEXPIRED,
591	NFSERR_INVAL,
592	NFSERR_IO,
593	NFSERR_MOVED,
594	NFSERR_NOFILEHANDLE,
595	NFSERR_RESOURCE,
596	NFSERR_SERVERFAULT,
597	NFSERR_STALE,
598	0,
599};
600
601static short nfsv4err_getfh[] = {
602	NFSERR_BADHANDLE,
603	NFSERR_BADHANDLE,
604	NFSERR_FHEXPIRED,
605	NFSERR_MOVED,
606	NFSERR_NOFILEHANDLE,
607	NFSERR_RESOURCE,
608	NFSERR_SERVERFAULT,
609	NFSERR_STALE,
610	0,
611};
612
613static short nfsv4err_link[] = {
614	NFSERR_IO,
615	NFSERR_ACCES,
616	NFSERR_BADCHAR,
617	NFSERR_BADHANDLE,
618	NFSERR_BADNAME,
619	NFSERR_BADXDR,
620	NFSERR_DELAY,
621	NFSERR_DQUOT,
622	NFSERR_EXIST,
623	NFSERR_FHEXPIRED,
624	NFSERR_FILEOPEN,
625	NFSERR_INVAL,
626	NFSERR_IO,
627	NFSERR_ISDIR,
628	NFSERR_MLINK,
629	NFSERR_MOVED,
630	NFSERR_NAMETOL,
631	NFSERR_NOENT,
632	NFSERR_NOFILEHANDLE,
633	NFSERR_NOSPC,
634	NFSERR_NOTDIR,
635	NFSERR_NOTSUPP,
636	NFSERR_RESOURCE,
637	NFSERR_ROFS,
638	NFSERR_SERVERFAULT,
639	NFSERR_STALE,
640	NFSERR_WRONGSEC,
641	NFSERR_XDEV,
642	0,
643};
644
645static short nfsv4err_lock[] = {
646	NFSERR_SERVERFAULT,
647	NFSERR_ACCES,
648	NFSERR_ADMINREVOKED,
649	NFSERR_BADHANDLE,
650	NFSERR_BADRANGE,
651	NFSERR_BADSEQID,
652	NFSERR_BADSTATEID,
653	NFSERR_BADXDR,
654	NFSERR_DEADLOCK,
655	NFSERR_DELAY,
656	NFSERR_DENIED,
657	NFSERR_EXPIRED,
658	NFSERR_FHEXPIRED,
659	NFSERR_GRACE,
660	NFSERR_INVAL,
661	NFSERR_ISDIR,
662	NFSERR_LEASEMOVED,
663	NFSERR_LOCKNOTSUPP,
664	NFSERR_LOCKRANGE,
665	NFSERR_MOVED,
666	NFSERR_NOFILEHANDLE,
667	NFSERR_NOGRACE,
668	NFSERR_OLDSTATEID,
669	NFSERR_OPENMODE,
670	NFSERR_RECLAIMBAD,
671	NFSERR_RECLAIMCONFLICT,
672	NFSERR_RESOURCE,
673	NFSERR_SERVERFAULT,
674	NFSERR_STALE,
675	NFSERR_STALECLIENTID,
676	NFSERR_STALESTATEID,
677	0,
678};
679
680static short nfsv4err_lockt[] = {
681	NFSERR_SERVERFAULT,
682	NFSERR_ACCES,
683	NFSERR_BADHANDLE,
684	NFSERR_BADRANGE,
685	NFSERR_BADXDR,
686	NFSERR_DELAY,
687	NFSERR_DENIED,
688	NFSERR_FHEXPIRED,
689	NFSERR_GRACE,
690	NFSERR_INVAL,
691	NFSERR_ISDIR,
692	NFSERR_LEASEMOVED,
693	NFSERR_LOCKRANGE,
694	NFSERR_MOVED,
695	NFSERR_NOFILEHANDLE,
696	NFSERR_RESOURCE,
697	NFSERR_SERVERFAULT,
698	NFSERR_STALE,
699	NFSERR_STALECLIENTID,
700	0,
701};
702
703static short nfsv4err_locku[] = {
704	NFSERR_SERVERFAULT,
705	NFSERR_ACCES,
706	NFSERR_ADMINREVOKED,
707	NFSERR_BADHANDLE,
708	NFSERR_BADRANGE,
709	NFSERR_BADSEQID,
710	NFSERR_BADSTATEID,
711	NFSERR_BADXDR,
712	NFSERR_EXPIRED,
713	NFSERR_FHEXPIRED,
714	NFSERR_GRACE,
715	NFSERR_INVAL,
716	NFSERR_ISDIR,
717	NFSERR_LEASEMOVED,
718	NFSERR_LOCKRANGE,
719	NFSERR_MOVED,
720	NFSERR_NOFILEHANDLE,
721	NFSERR_OLDSTATEID,
722	NFSERR_RESOURCE,
723	NFSERR_SERVERFAULT,
724	NFSERR_STALE,
725	NFSERR_STALESTATEID,
726	0,
727};
728
729static short nfsv4err_lookup[] = {
730	NFSERR_IO,
731	NFSERR_ACCES,
732	NFSERR_BADCHAR,
733	NFSERR_BADHANDLE,
734	NFSERR_BADNAME,
735	NFSERR_BADXDR,
736	NFSERR_FHEXPIRED,
737	NFSERR_INVAL,
738	NFSERR_IO,
739	NFSERR_MOVED,
740	NFSERR_NAMETOL,
741	NFSERR_NOENT,
742	NFSERR_NOFILEHANDLE,
743	NFSERR_NOTDIR,
744	NFSERR_RESOURCE,
745	NFSERR_SERVERFAULT,
746	NFSERR_STALE,
747	NFSERR_SYMLINK,
748	NFSERR_WRONGSEC,
749	0,
750};
751
752static short nfsv4err_lookupp[] = {
753	NFSERR_IO,
754	NFSERR_ACCES,
755	NFSERR_BADHANDLE,
756	NFSERR_FHEXPIRED,
757	NFSERR_IO,
758	NFSERR_MOVED,
759	NFSERR_NOENT,
760	NFSERR_NOFILEHANDLE,
761	NFSERR_NOTDIR,
762	NFSERR_RESOURCE,
763	NFSERR_SERVERFAULT,
764	NFSERR_STALE,
765	0,
766};
767
768static short nfsv4err_nverify[] = {
769	NFSERR_IO,
770	NFSERR_ACCES,
771	NFSERR_ATTRNOTSUPP,
772	NFSERR_BADCHAR,
773	NFSERR_BADHANDLE,
774	NFSERR_BADXDR,
775	NFSERR_DELAY,
776	NFSERR_FHEXPIRED,
777	NFSERR_INVAL,
778	NFSERR_IO,
779	NFSERR_MOVED,
780	NFSERR_NOFILEHANDLE,
781	NFSERR_RESOURCE,
782	NFSERR_SAME,
783	NFSERR_SERVERFAULT,
784	NFSERR_STALE,
785	0,
786};
787
788static short nfsv4err_open[] = {
789	NFSERR_IO,
790	NFSERR_ACCES,
791	NFSERR_ADMINREVOKED,
792	NFSERR_ATTRNOTSUPP,
793	NFSERR_BADCHAR,
794	NFSERR_BADHANDLE,
795	NFSERR_BADNAME,
796	NFSERR_BADOWNER,
797	NFSERR_BADSEQID,
798	NFSERR_BADXDR,
799	NFSERR_DELAY,
800	NFSERR_DQUOT,
801	NFSERR_EXIST,
802	NFSERR_EXPIRED,
803	NFSERR_FHEXPIRED,
804	NFSERR_GRACE,
805	NFSERR_IO,
806	NFSERR_INVAL,
807	NFSERR_ISDIR,
808	NFSERR_LEASEMOVED,
809	NFSERR_MOVED,
810	NFSERR_NAMETOL,
811	NFSERR_NOENT,
812	NFSERR_NOFILEHANDLE,
813	NFSERR_NOGRACE,
814	NFSERR_NOSPC,
815	NFSERR_NOTDIR,
816	NFSERR_NOTSUPP,
817	NFSERR_PERM,
818	NFSERR_RECLAIMBAD,
819	NFSERR_RECLAIMCONFLICT,
820	NFSERR_RESOURCE,
821	NFSERR_ROFS,
822	NFSERR_SERVERFAULT,
823	NFSERR_SHAREDENIED,
824	NFSERR_STALE,
825	NFSERR_STALECLIENTID,
826	NFSERR_SYMLINK,
827	NFSERR_WRONGSEC,
828	0,
829};
830
831static short nfsv4err_openattr[] = {
832	NFSERR_IO,
833	NFSERR_ACCES,
834	NFSERR_BADHANDLE,
835	NFSERR_BADXDR,
836	NFSERR_DELAY,
837	NFSERR_DQUOT,
838	NFSERR_FHEXPIRED,
839	NFSERR_IO,
840	NFSERR_MOVED,
841	NFSERR_NOENT,
842	NFSERR_NOFILEHANDLE,
843	NFSERR_NOSPC,
844	NFSERR_NOTSUPP,
845	NFSERR_RESOURCE,
846	NFSERR_ROFS,
847	NFSERR_SERVERFAULT,
848	NFSERR_STALE,
849	0,
850};
851
852static short nfsv4err_openconfirm[] = {
853	NFSERR_SERVERFAULT,
854	NFSERR_ADMINREVOKED,
855	NFSERR_BADHANDLE,
856	NFSERR_BADSEQID,
857	NFSERR_BADSTATEID,
858	NFSERR_BADXDR,
859	NFSERR_EXPIRED,
860	NFSERR_FHEXPIRED,
861	NFSERR_INVAL,
862	NFSERR_ISDIR,
863	NFSERR_MOVED,
864	NFSERR_NOFILEHANDLE,
865	NFSERR_OLDSTATEID,
866	NFSERR_RESOURCE,
867	NFSERR_SERVERFAULT,
868	NFSERR_STALE,
869	NFSERR_STALESTATEID,
870	0,
871};
872
873static short nfsv4err_opendowngrade[] = {
874	NFSERR_SERVERFAULT,
875	NFSERR_ADMINREVOKED,
876	NFSERR_BADHANDLE,
877	NFSERR_BADSEQID,
878	NFSERR_BADSTATEID,
879	NFSERR_BADXDR,
880	NFSERR_EXPIRED,
881	NFSERR_FHEXPIRED,
882	NFSERR_INVAL,
883	NFSERR_MOVED,
884	NFSERR_NOFILEHANDLE,
885	NFSERR_OLDSTATEID,
886	NFSERR_RESOURCE,
887	NFSERR_SERVERFAULT,
888	NFSERR_STALE,
889	NFSERR_STALESTATEID,
890	0,
891};
892
893static short nfsv4err_putfh[] = {
894	NFSERR_SERVERFAULT,
895	NFSERR_BADHANDLE,
896	NFSERR_BADXDR,
897	NFSERR_FHEXPIRED,
898	NFSERR_MOVED,
899	NFSERR_RESOURCE,
900	NFSERR_SERVERFAULT,
901	NFSERR_STALE,
902	NFSERR_WRONGSEC,
903	0,
904};
905
906static short nfsv4err_putpubfh[] = {
907	NFSERR_SERVERFAULT,
908	NFSERR_RESOURCE,
909	NFSERR_SERVERFAULT,
910	NFSERR_WRONGSEC,
911	0,
912};
913
914static short nfsv4err_putrootfh[] = {
915	NFSERR_SERVERFAULT,
916	NFSERR_RESOURCE,
917	NFSERR_SERVERFAULT,
918	NFSERR_WRONGSEC,
919	0,
920};
921
922static short nfsv4err_read[] = {
923	NFSERR_IO,
924	NFSERR_ACCES,
925	NFSERR_ADMINREVOKED,
926	NFSERR_BADHANDLE,
927	NFSERR_BADSTATEID,
928	NFSERR_BADXDR,
929	NFSERR_DELAY,
930	NFSERR_EXPIRED,
931	NFSERR_FHEXPIRED,
932	NFSERR_GRACE,
933	NFSERR_IO,
934	NFSERR_INVAL,
935	NFSERR_ISDIR,
936	NFSERR_LEASEMOVED,
937	NFSERR_LOCKED,
938	NFSERR_MOVED,
939	NFSERR_NOFILEHANDLE,
940	NFSERR_NXIO,
941	NFSERR_OLDSTATEID,
942	NFSERR_OPENMODE,
943	NFSERR_RESOURCE,
944	NFSERR_SERVERFAULT,
945	NFSERR_STALE,
946	NFSERR_STALESTATEID,
947	0,
948};
949
950static short nfsv4err_readdir[] = {
951	NFSERR_IO,
952	NFSERR_ACCES,
953	NFSERR_BADHANDLE,
954	NFSERR_BAD_COOKIE,
955	NFSERR_BADXDR,
956	NFSERR_DELAY,
957	NFSERR_FHEXPIRED,
958	NFSERR_INVAL,
959	NFSERR_IO,
960	NFSERR_MOVED,
961	NFSERR_NOFILEHANDLE,
962	NFSERR_NOTDIR,
963	NFSERR_NOTSAME,
964	NFSERR_RESOURCE,
965	NFSERR_SERVERFAULT,
966	NFSERR_STALE,
967	NFSERR_TOOSMALL,
968	0,
969};
970
971static short nfsv4err_readlink[] = {
972	NFSERR_IO,
973	NFSERR_ACCES,
974	NFSERR_BADHANDLE,
975	NFSERR_DELAY,
976	NFSERR_FHEXPIRED,
977	NFSERR_INVAL,
978	NFSERR_IO,
979	NFSERR_ISDIR,
980	NFSERR_MOVED,
981	NFSERR_NOFILEHANDLE,
982	NFSERR_NOTSUPP,
983	NFSERR_RESOURCE,
984	NFSERR_SERVERFAULT,
985	NFSERR_STALE,
986	0,
987};
988
989static short nfsv4err_remove[] = {
990	NFSERR_IO,
991	NFSERR_ACCES,
992	NFSERR_BADCHAR,
993	NFSERR_BADHANDLE,
994	NFSERR_BADNAME,
995	NFSERR_BADXDR,
996	NFSERR_DELAY,
997	NFSERR_FHEXPIRED,
998	NFSERR_FILEOPEN,
999	NFSERR_INVAL,
1000	NFSERR_IO,
1001	NFSERR_MOVED,
1002	NFSERR_NAMETOL,
1003	NFSERR_NOENT,
1004	NFSERR_NOFILEHANDLE,
1005	NFSERR_NOTDIR,
1006	NFSERR_NOTEMPTY,
1007	NFSERR_RESOURCE,
1008	NFSERR_ROFS,
1009	NFSERR_SERVERFAULT,
1010	NFSERR_STALE,
1011	0,
1012};
1013
1014static short nfsv4err_rename[] = {
1015	NFSERR_IO,
1016	NFSERR_ACCES,
1017	NFSERR_BADCHAR,
1018	NFSERR_BADHANDLE,
1019	NFSERR_BADNAME,
1020	NFSERR_BADXDR,
1021	NFSERR_DELAY,
1022	NFSERR_DQUOT,
1023	NFSERR_EXIST,
1024	NFSERR_FHEXPIRED,
1025	NFSERR_FILEOPEN,
1026	NFSERR_INVAL,
1027	NFSERR_IO,
1028	NFSERR_MOVED,
1029	NFSERR_NAMETOL,
1030	NFSERR_NOENT,
1031	NFSERR_NOFILEHANDLE,
1032	NFSERR_NOSPC,
1033	NFSERR_NOTDIR,
1034	NFSERR_NOTEMPTY,
1035	NFSERR_RESOURCE,
1036	NFSERR_ROFS,
1037	NFSERR_SERVERFAULT,
1038	NFSERR_STALE,
1039	NFSERR_WRONGSEC,
1040	NFSERR_XDEV,
1041	0,
1042};
1043
1044static short nfsv4err_renew[] = {
1045	NFSERR_SERVERFAULT,
1046	NFSERR_ACCES,
1047	NFSERR_ADMINREVOKED,
1048	NFSERR_BADXDR,
1049	NFSERR_CBPATHDOWN,
1050	NFSERR_EXPIRED,
1051	NFSERR_LEASEMOVED,
1052	NFSERR_RESOURCE,
1053	NFSERR_SERVERFAULT,
1054	NFSERR_STALECLIENTID,
1055	0,
1056};
1057
1058static short nfsv4err_restorefh[] = {
1059	NFSERR_SERVERFAULT,
1060	NFSERR_BADHANDLE,
1061	NFSERR_FHEXPIRED,
1062	NFSERR_MOVED,
1063	NFSERR_RESOURCE,
1064	NFSERR_RESTOREFH,
1065	NFSERR_SERVERFAULT,
1066	NFSERR_STALE,
1067	NFSERR_WRONGSEC,
1068	0,
1069};
1070
1071static short nfsv4err_savefh[] = {
1072	NFSERR_SERVERFAULT,
1073	NFSERR_BADHANDLE,
1074	NFSERR_FHEXPIRED,
1075	NFSERR_MOVED,
1076	NFSERR_NOFILEHANDLE,
1077	NFSERR_RESOURCE,
1078	NFSERR_SERVERFAULT,
1079	NFSERR_STALE,
1080	0,
1081};
1082
1083static short nfsv4err_secinfo[] = {
1084	NFSERR_SERVERFAULT,
1085	NFSERR_ACCES,
1086	NFSERR_BADCHAR,
1087	NFSERR_BADHANDLE,
1088	NFSERR_BADNAME,
1089	NFSERR_BADXDR,
1090	NFSERR_FHEXPIRED,
1091	NFSERR_INVAL,
1092	NFSERR_MOVED,
1093	NFSERR_NAMETOL,
1094	NFSERR_NOENT,
1095	NFSERR_NOFILEHANDLE,
1096	NFSERR_NOTDIR,
1097	NFSERR_RESOURCE,
1098	NFSERR_SERVERFAULT,
1099	NFSERR_STALE,
1100	0,
1101};
1102
1103static short nfsv4err_setattr[] = {
1104	NFSERR_IO,
1105	NFSERR_ACCES,
1106	NFSERR_ADMINREVOKED,
1107	NFSERR_ATTRNOTSUPP,
1108	NFSERR_BADCHAR,
1109	NFSERR_BADHANDLE,
1110	NFSERR_BADOWNER,
1111	NFSERR_BADSTATEID,
1112	NFSERR_BADXDR,
1113	NFSERR_DELAY,
1114	NFSERR_DQUOT,
1115	NFSERR_EXPIRED,
1116	NFSERR_FBIG,
1117	NFSERR_FHEXPIRED,
1118	NFSERR_GRACE,
1119	NFSERR_INVAL,
1120	NFSERR_IO,
1121	NFSERR_ISDIR,
1122	NFSERR_LOCKED,
1123	NFSERR_MOVED,
1124	NFSERR_NOFILEHANDLE,
1125	NFSERR_NOSPC,
1126	NFSERR_OLDSTATEID,
1127	NFSERR_OPENMODE,
1128	NFSERR_PERM,
1129	NFSERR_RESOURCE,
1130	NFSERR_ROFS,
1131	NFSERR_SERVERFAULT,
1132	NFSERR_STALE,
1133	NFSERR_STALESTATEID,
1134	0,
1135};
1136
1137static short nfsv4err_setclientid[] = {
1138	NFSERR_SERVERFAULT,
1139	NFSERR_BADXDR,
1140	NFSERR_CLIDINUSE,
1141	NFSERR_INVAL,
1142	NFSERR_RESOURCE,
1143	NFSERR_SERVERFAULT,
1144	0,
1145};
1146
1147static short nfsv4err_setclientidconfirm[] = {
1148	NFSERR_SERVERFAULT,
1149	NFSERR_BADXDR,
1150	NFSERR_CLIDINUSE,
1151	NFSERR_RESOURCE,
1152	NFSERR_SERVERFAULT,
1153	NFSERR_STALECLIENTID,
1154	0,
1155};
1156
1157static short nfsv4err_verify[] = {
1158	NFSERR_SERVERFAULT,
1159	NFSERR_ACCES,
1160	NFSERR_ATTRNOTSUPP,
1161	NFSERR_BADCHAR,
1162	NFSERR_BADHANDLE,
1163	NFSERR_BADXDR,
1164	NFSERR_DELAY,
1165	NFSERR_FHEXPIRED,
1166	NFSERR_INVAL,
1167	NFSERR_MOVED,
1168	NFSERR_NOFILEHANDLE,
1169	NFSERR_NOTSAME,
1170	NFSERR_RESOURCE,
1171	NFSERR_SERVERFAULT,
1172	NFSERR_STALE,
1173	0,
1174};
1175
1176static short nfsv4err_write[] = {
1177	NFSERR_IO,
1178	NFSERR_ACCES,
1179	NFSERR_ADMINREVOKED,
1180	NFSERR_BADHANDLE,
1181	NFSERR_BADSTATEID,
1182	NFSERR_BADXDR,
1183	NFSERR_DELAY,
1184	NFSERR_DQUOT,
1185	NFSERR_EXPIRED,
1186	NFSERR_FBIG,
1187	NFSERR_FHEXPIRED,
1188	NFSERR_GRACE,
1189	NFSERR_INVAL,
1190	NFSERR_IO,
1191	NFSERR_ISDIR,
1192	NFSERR_LEASEMOVED,
1193	NFSERR_LOCKED,
1194	NFSERR_MOVED,
1195	NFSERR_NOFILEHANDLE,
1196	NFSERR_NOSPC,
1197	NFSERR_NXIO,
1198	NFSERR_OLDSTATEID,
1199	NFSERR_OPENMODE,
1200	NFSERR_RESOURCE,
1201	NFSERR_ROFS,
1202	NFSERR_SERVERFAULT,
1203	NFSERR_STALE,
1204	NFSERR_STALESTATEID,
1205	0,
1206};
1207
1208static short nfsv4err_releaselockowner[] = {
1209	NFSERR_SERVERFAULT,
1210	NFSERR_ADMINREVOKED,
1211	NFSERR_BADXDR,
1212	NFSERR_EXPIRED,
1213	NFSERR_LEASEMOVED,
1214	NFSERR_LOCKSHELD,
1215	NFSERR_RESOURCE,
1216	NFSERR_SERVERFAULT,
1217	NFSERR_STALECLIENTID,
1218	0,
1219};
1220
1221static short *nfsrv_v4errmap[] = {
1222	nfsv4err_null,
1223	nfsv4err_null,
1224	nfsv4err_null,
1225	nfsv4err_access,
1226	nfsv4err_close,
1227	nfsv4err_commit,
1228	nfsv4err_create,
1229	nfsv4err_delegpurge,
1230	nfsv4err_delegreturn,
1231	nfsv4err_getattr,
1232	nfsv4err_getfh,
1233	nfsv4err_link,
1234	nfsv4err_lock,
1235	nfsv4err_lockt,
1236	nfsv4err_locku,
1237	nfsv4err_lookup,
1238	nfsv4err_lookupp,
1239	nfsv4err_nverify,
1240	nfsv4err_open,
1241	nfsv4err_openattr,
1242	nfsv4err_openconfirm,
1243	nfsv4err_opendowngrade,
1244	nfsv4err_putfh,
1245	nfsv4err_putpubfh,
1246	nfsv4err_putrootfh,
1247	nfsv4err_read,
1248	nfsv4err_readdir,
1249	nfsv4err_readlink,
1250	nfsv4err_remove,
1251	nfsv4err_rename,
1252	nfsv4err_renew,
1253	nfsv4err_restorefh,
1254	nfsv4err_savefh,
1255	nfsv4err_secinfo,
1256	nfsv4err_setattr,
1257	nfsv4err_setclientid,
1258	nfsv4err_setclientidconfirm,
1259	nfsv4err_verify,
1260	nfsv4err_write,
1261	nfsv4err_releaselockowner,
1262};
1263
1264/*
1265 * A fiddled version of m_adj() that ensures null fill to a long
1266 * boundary and only trims off the back end
1267 */
1268APPLESTATIC void
1269nfsrv_adj(mbuf_t mp, int len, int nul)
1270{
1271	mbuf_t m;
1272	int count, i;
1273	char *cp;
1274
1275	/*
1276	 * Trim from tail.  Scan the mbuf chain,
1277	 * calculating its length and finding the last mbuf.
1278	 * If the adjustment only affects this mbuf, then just
1279	 * adjust and return.  Otherwise, rescan and truncate
1280	 * after the remaining size.
1281	 */
1282	count = 0;
1283	m = mp;
1284	for (;;) {
1285		count += mbuf_len(m);
1286		if (mbuf_next(m) == NULL)
1287			break;
1288		m = mbuf_next(m);
1289	}
1290	if (mbuf_len(m) > len) {
1291		mbuf_setlen(m, mbuf_len(m) - len);
1292		if (nul > 0) {
1293			cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1294			for (i = 0; i < nul; i++)
1295				*cp++ = '\0';
1296		}
1297		return;
1298	}
1299	count -= len;
1300	if (count < 0)
1301		count = 0;
1302	/*
1303	 * Correct length for chain is "count".
1304	 * Find the mbuf with last data, adjust its length,
1305	 * and toss data from remaining mbufs on chain.
1306	 */
1307	for (m = mp; m; m = mbuf_next(m)) {
1308		if (mbuf_len(m) >= count) {
1309			mbuf_setlen(m, count);
1310			if (nul > 0) {
1311				cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1312				for (i = 0; i < nul; i++)
1313					*cp++ = '\0';
1314			}
1315			break;
1316		}
1317		count -= mbuf_len(m);
1318	}
1319	for (m = mbuf_next(m); m; m = mbuf_next(m))
1320		mbuf_setlen(m, 0);
1321}
1322
1323/*
1324 * Make these functions instead of macros, so that the kernel text size
1325 * doesn't get too big...
1326 */
1327APPLESTATIC void
1328nfsrv_wcc(struct nfsrv_descript *nd, int before_ret,
1329    struct nfsvattr *before_nvap, int after_ret, struct nfsvattr *after_nvap)
1330{
1331	u_int32_t *tl;
1332
1333	if (before_ret) {
1334		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1335		*tl = newnfs_false;
1336	} else {
1337		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1338		*tl++ = newnfs_true;
1339		txdr_hyper(before_nvap->na_size, tl);
1340		tl += 2;
1341		txdr_nfsv3time(&(before_nvap->na_mtime), tl);
1342		tl += 2;
1343		txdr_nfsv3time(&(before_nvap->na_ctime), tl);
1344	}
1345	nfsrv_postopattr(nd, after_ret, after_nvap);
1346}
1347
1348APPLESTATIC void
1349nfsrv_postopattr(struct nfsrv_descript *nd, int after_ret,
1350    struct nfsvattr *after_nvap)
1351{
1352	u_int32_t *tl;
1353
1354	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1355	if (after_ret)
1356		*tl = newnfs_false;
1357	else {
1358		*tl = newnfs_true;
1359		nfsrv_fillattr(nd, after_nvap);
1360	}
1361}
1362
1363/*
1364 * Fill in file attributes for V2 and 3. For V4, call a separate
1365 * routine that sifts through all the attribute bits.
1366 */
1367APPLESTATIC void
1368nfsrv_fillattr(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1369{
1370	struct nfs_fattr *fp;
1371	int fattr_size;
1372
1373	/*
1374	 * Build space for the attribute structure.
1375	 */
1376	if (nd->nd_flag & ND_NFSV3)
1377		fattr_size = NFSX_V3FATTR;
1378	else
1379		fattr_size = NFSX_V2FATTR;
1380	NFSM_BUILD(fp, struct nfs_fattr *, fattr_size);
1381
1382	/*
1383	 * Now just fill it all in.
1384	 */
1385	fp->fa_nlink = txdr_unsigned(nvap->na_nlink);
1386	fp->fa_uid = txdr_unsigned(nvap->na_uid);
1387	fp->fa_gid = txdr_unsigned(nvap->na_gid);
1388	if (nd->nd_flag & ND_NFSV3) {
1389		fp->fa_type = vtonfsv34_type(nvap->na_type);
1390		fp->fa_mode = vtonfsv34_mode(nvap->na_mode);
1391		txdr_hyper(nvap->na_size, &fp->fa3_size);
1392		txdr_hyper(nvap->na_bytes, &fp->fa3_used);
1393		fp->fa3_rdev.specdata1 = txdr_unsigned(NFSMAJOR(nvap->na_rdev));
1394		fp->fa3_rdev.specdata2 = txdr_unsigned(NFSMINOR(nvap->na_rdev));
1395		fp->fa3_fsid.nfsuquad[0] = 0;
1396		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(nvap->na_fsid);
1397		fp->fa3_fileid.nfsuquad[0] = 0;
1398		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(nvap->na_fileid);
1399		txdr_nfsv3time(&nvap->na_atime, &fp->fa3_atime);
1400		txdr_nfsv3time(&nvap->na_mtime, &fp->fa3_mtime);
1401		txdr_nfsv3time(&nvap->na_ctime, &fp->fa3_ctime);
1402	} else {
1403		fp->fa_type = vtonfsv2_type(nvap->na_type);
1404		fp->fa_mode = vtonfsv2_mode(nvap->na_type, nvap->na_mode);
1405		fp->fa2_size = txdr_unsigned(nvap->na_size);
1406		fp->fa2_blocksize = txdr_unsigned(nvap->na_blocksize);
1407		if (nvap->na_type == VFIFO)
1408			fp->fa2_rdev = 0xffffffff;
1409		else
1410			fp->fa2_rdev = txdr_unsigned(nvap->na_rdev);
1411		fp->fa2_blocks = txdr_unsigned(nvap->na_bytes / NFS_FABLKSIZE);
1412		fp->fa2_fsid = txdr_unsigned(nvap->na_fsid);
1413		fp->fa2_fileid = txdr_unsigned(nvap->na_fileid);
1414		txdr_nfsv2time(&nvap->na_atime, &fp->fa2_atime);
1415		txdr_nfsv2time(&nvap->na_mtime, &fp->fa2_mtime);
1416		txdr_nfsv2time(&nvap->na_ctime, &fp->fa2_ctime);
1417	}
1418}
1419
1420/*
1421 * This function gets a file handle out of an mbuf list.
1422 * It returns 0 for success, EBADRPC otherwise.
1423 * If sets the third flagp argument to 1 if the file handle is
1424 * the public file handle.
1425 * For NFSv4, if the length is incorrect, set nd_repstat == NFSERR_BADHANDLE
1426 */
1427APPLESTATIC int
1428nfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
1429{
1430	u_int32_t *tl;
1431	int error = 0, len, copylen;
1432
1433	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1434		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1435		len = fxdr_unsigned(int, *tl);
1436		if (len == 0 && nfs_pubfhset && (nd->nd_flag & ND_NFSV3) &&
1437		    nd->nd_procnum == NFSPROC_LOOKUP) {
1438			nd->nd_flag |= ND_PUBLOOKUP;
1439			goto nfsmout;
1440		}
1441		if (len < NFSRV_MINFH || len > NFSRV_MAXFH) {
1442			if (nd->nd_flag & ND_NFSV4) {
1443			    if (len > 0 && len <= NFSX_V4FHMAX) {
1444				error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1445				if (error)
1446					goto nfsmout;
1447				nd->nd_repstat = NFSERR_BADHANDLE;
1448				goto nfsmout;
1449			    } else {
1450				    error = EBADRPC;
1451				    goto nfsmout;
1452			    }
1453			} else {
1454				error = EBADRPC;
1455				goto nfsmout;
1456			}
1457		}
1458		copylen = len;
1459	} else {
1460		/*
1461		 * For NFSv2, the file handle is always 32 bytes on the
1462		 * wire, but this server only cares about the first
1463		 * NFSRV_MAXFH bytes.
1464		 */
1465		len = NFSX_V2FH;
1466		copylen = NFSRV_MAXFH;
1467	}
1468	NFSM_DISSECT(tl, u_int32_t *, len);
1469	if ((nd->nd_flag & ND_NFSV2) && nfs_pubfhset &&
1470	    nd->nd_procnum == NFSPROC_LOOKUP &&
1471	    !NFSBCMP((caddr_t)tl, nfs_v2pubfh, NFSX_V2FH)) {
1472		nd->nd_flag |= ND_PUBLOOKUP;
1473		goto nfsmout;
1474	}
1475	NFSBCOPY(tl, (caddr_t)fhp->nfsrvfh_data, copylen);
1476	fhp->nfsrvfh_len = copylen;
1477nfsmout:
1478	NFSEXITCODE2(error, nd);
1479	return (error);
1480}
1481
1482/*
1483 * Map errnos to NFS error numbers. For Version 3 and 4 also filter out error
1484 * numbers not specified for the associated procedure.
1485 * NFSPROC_NOOP is a special case, where the high order bits of nd_repstat
1486 * should be cleared. NFSPROC_NOOP is used to return errors when a valid
1487 * RPC procedure is not involved.
1488 * Returns the error number in XDR.
1489 */
1490APPLESTATIC int
1491nfsd_errmap(struct nfsrv_descript *nd)
1492{
1493	short *defaulterrp, *errp;
1494
1495	if (!nd->nd_repstat)
1496		return (0);
1497	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1498		if (nd->nd_procnum == NFSPROC_NOOP)
1499			return (txdr_unsigned(nd->nd_repstat & 0xffff));
1500		if (nd->nd_flag & ND_NFSV3)
1501		    errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1502		else if (nd->nd_repstat == EBADRPC)
1503			return (txdr_unsigned(NFSERR_BADXDR));
1504		else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
1505			 nd->nd_repstat == NFSERR_OPILLEGAL)
1506			return (txdr_unsigned(nd->nd_repstat));
1507		else if ((nd->nd_flag & ND_NFSV41) != 0) {
1508			if (nd->nd_repstat == EOPNOTSUPP)
1509				nd->nd_repstat = NFSERR_NOTSUPP;
1510			nd->nd_repstat = nfsrv_isannfserr(nd->nd_repstat);
1511			return (txdr_unsigned(nd->nd_repstat));
1512		} else
1513		    errp = defaulterrp = nfsrv_v4errmap[nd->nd_procnum];
1514		while (*++errp)
1515			if (*errp == nd->nd_repstat)
1516				return (txdr_unsigned(nd->nd_repstat));
1517		return (txdr_unsigned(*defaulterrp));
1518	}
1519	if (nd->nd_repstat <= NFSERR_REMOTE)
1520		return (txdr_unsigned(nfsrv_v2errmap[nd->nd_repstat - 1]));
1521	return (txdr_unsigned(NFSERR_IO));
1522}
1523
1524/*
1525 * Check to see if the error is a valid NFS one. If not, replace it with
1526 * NFSERR_IO.
1527 */
1528static u_int32_t
1529nfsrv_isannfserr(u_int32_t errval)
1530{
1531
1532	if (errval == NFSERR_OK)
1533		return (errval);
1534	if (errval >= NFSERR_BADHANDLE && errval <= NFSERR_DELEGREVOKED)
1535		return (errval);
1536	if (errval > 0 && errval <= NFSERR_REMOTE)
1537		return (nfsrv_v2errmap[errval - 1]);
1538	return (NFSERR_IO);
1539}
1540
1541/*
1542 * Check to see if setting a uid/gid is permitted when creating a new
1543 * file object. (Called when uid and/or gid is specified in the
1544 * settable attributes for V4.
1545 */
1546APPLESTATIC int
1547nfsrv_checkuidgid(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1548{
1549	int error = 0;
1550
1551	/*
1552	 * If not setting either uid nor gid, it's OK.
1553	 */
1554	if (NFSVNO_NOTSETUID(nvap) && NFSVNO_NOTSETGID(nvap))
1555		goto out;
1556	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid == nfsrv_defaultuid &&
1557           enable_nobodycheck == 1)
1558	    || (NFSVNO_ISSETGID(nvap) && nvap->na_gid == nfsrv_defaultgid &&
1559           enable_nogroupcheck == 1)) {
1560		error = NFSERR_BADOWNER;
1561		goto out;
1562	}
1563	if (nd->nd_cred->cr_uid == 0)
1564		goto out;
1565	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid != nd->nd_cred->cr_uid) ||
1566	    (NFSVNO_ISSETGID(nvap) && nvap->na_gid != nd->nd_cred->cr_gid &&
1567	    !groupmember(nvap->na_gid, nd->nd_cred)))
1568		error = NFSERR_PERM;
1569
1570out:
1571	NFSEXITCODE2(error, nd);
1572	return (error);
1573}
1574
1575/*
1576 * and this routine fixes up the settable attributes for V4 if allowed
1577 * by nfsrv_checkuidgid().
1578 */
1579APPLESTATIC void
1580nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
1581    struct nfsvattr *nvap, NFSACL_T *aclp, NFSPROC_T *p, nfsattrbit_t *attrbitp,
1582    struct nfsexstuff *exp)
1583{
1584	int change = 0;
1585	struct nfsvattr nva;
1586	uid_t tuid;
1587	int error;
1588	nfsattrbit_t nattrbits;
1589
1590	/*
1591	 * Maybe this should be done for V2 and 3 but it never has been
1592	 * and nobody seems to be upset, so I think it's best not to change
1593	 * the V2 and 3 semantics.
1594	 */
1595	if ((nd->nd_flag & ND_NFSV4) == 0)
1596		goto out;
1597	NFSVNO_ATTRINIT(&nva);
1598	NFSZERO_ATTRBIT(&nattrbits);
1599	tuid = nd->nd_cred->cr_uid;
1600	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) &&
1601	    NFSVNO_ISSETUID(nvap) &&
1602	    nvap->na_uid != nd->nd_cred->cr_uid) {
1603		if (nd->nd_cred->cr_uid == 0) {
1604			nva.na_uid = nvap->na_uid;
1605			change++;
1606			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNER);
1607		} else {
1608			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNER);
1609		}
1610	}
1611	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESSSET) &&
1612	    NFSVNO_ISSETATIME(nvap)) {
1613		nva.na_atime = nvap->na_atime;
1614		change++;
1615		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEACCESSSET);
1616	}
1617	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFYSET) &&
1618	    NFSVNO_ISSETMTIME(nvap)) {
1619		nva.na_mtime = nvap->na_mtime;
1620		change++;
1621		NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEMODIFYSET);
1622	}
1623	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) &&
1624	    NFSVNO_ISSETGID(nvap)) {
1625		if (nvap->na_gid == nd->nd_cred->cr_gid ||
1626		    groupmember(nvap->na_gid, nd->nd_cred)) {
1627			nd->nd_cred->cr_uid = 0;
1628			nva.na_gid = nvap->na_gid;
1629			change++;
1630			NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNERGROUP);
1631		} else {
1632			NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP);
1633		}
1634	}
1635	if (change) {
1636		error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
1637		if (error) {
1638			NFSCLRALL_ATTRBIT(attrbitp, &nattrbits);
1639		}
1640	}
1641	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) &&
1642	    NFSVNO_ISSETSIZE(nvap) && nvap->na_size != (u_quad_t)0) {
1643		NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_SIZE);
1644	}
1645#ifdef NFS4_ACL_EXTATTR_NAME
1646	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL) &&
1647	    nfsrv_useacl != 0 && aclp != NULL) {
1648		if (aclp->acl_cnt > 0) {
1649			error = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
1650			if (error) {
1651				NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1652			}
1653		}
1654	} else
1655#endif
1656	NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1657	nd->nd_cred->cr_uid = tuid;
1658
1659out:
1660	NFSEXITCODE2(0, nd);
1661}
1662
1663/*
1664 * Translate an ASCII hex digit to it's binary value. Return -1 if the
1665 * char isn't a hex digit.
1666 */
1667static char
1668nfsrv_hexdigit(char c, int *err)
1669{
1670
1671	*err = 0;
1672	if (c >= '0' && c <= '9')
1673		return (c - '0');
1674	if (c >= 'a' && c <= 'f')
1675		return (c - 'a' + ((char)10));
1676	if (c >= 'A' && c <= 'F')
1677		return (c - 'A' + ((char)10));
1678	/* Not valid ! */
1679	*err = 1;
1680	return (1);	/* BOGUS */
1681}
1682
1683/*
1684 * Check to see if NFSERR_MOVED can be returned for this op. Return 1 iff
1685 * it can be.
1686 */
1687APPLESTATIC int
1688nfsrv_errmoved(int op)
1689{
1690	short *errp;
1691
1692	errp = nfsrv_v4errmap[op];
1693	while (*errp != 0) {
1694		if (*errp == NFSERR_MOVED)
1695			return (1);
1696		errp++;
1697	}
1698	return (0);
1699}
1700
1701/*
1702 * Fill in attributes for a Referral.
1703 * (Return the number of bytes of XDR created.)
1704 */
1705APPLESTATIC int
1706nfsrv_putreferralattr(struct nfsrv_descript *nd, nfsattrbit_t *retbitp,
1707    struct nfsreferral *refp, int getattr, int *reterrp)
1708{
1709	u_int32_t *tl, *retnump;
1710	u_char *cp, *cp2;
1711	int prefixnum, retnum = 0, i, len, bitpos, rderrbit = 0, nonrefbit = 0;
1712	int fslocationsbit = 0;
1713	nfsattrbit_t tmpbits, refbits;
1714
1715	NFSREFERRAL_ATTRBIT(&refbits);
1716	if (getattr)
1717		NFSCLRBIT_ATTRBIT(&refbits, NFSATTRBIT_RDATTRERROR);
1718	else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_RDATTRERROR))
1719		rderrbit = 1;
1720	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_FSLOCATIONS))
1721		fslocationsbit = 1;
1722
1723	/*
1724	 * Check for the case where unsupported referral attributes are
1725	 * requested.
1726	 */
1727	NFSSET_ATTRBIT(&tmpbits, retbitp);
1728	NFSCLRALL_ATTRBIT(&tmpbits, &refbits);
1729	if (NFSNONZERO_ATTRBIT(&tmpbits))
1730		nonrefbit = 1;
1731
1732	if (nonrefbit && !fslocationsbit && (getattr || !rderrbit)) {
1733		*reterrp = NFSERR_MOVED;
1734		return (0);
1735	}
1736
1737	/*
1738	 * Now we can fill in the attributes.
1739	 */
1740	NFSSET_ATTRBIT(&tmpbits, retbitp);
1741	NFSCLRNOT_ATTRBIT(&tmpbits, &refbits);
1742
1743	/*
1744	 * Put out the attribute bitmap for the ones being filled in
1745	 * and get the field for the number of attributes returned.
1746	 */
1747	prefixnum = nfsrv_putattrbit(nd, &tmpbits);
1748	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1749	prefixnum += NFSX_UNSIGNED;
1750
1751	/*
1752	 * Now, loop around filling in the attributes for each bit set.
1753	 */
1754	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1755	    if (NFSISSET_ATTRBIT(&tmpbits, bitpos)) {
1756		switch (bitpos) {
1757		case NFSATTRBIT_TYPE:
1758			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1759			*tl = txdr_unsigned(NFDIR);
1760			retnum += NFSX_UNSIGNED;
1761			break;
1762		case NFSATTRBIT_FSID:
1763			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
1764			*tl++ = 0;
1765			*tl++ = txdr_unsigned(NFSV4ROOT_FSID0);
1766			*tl++ = 0;
1767			*tl = txdr_unsigned(NFSV4ROOT_REFERRAL);
1768			retnum += NFSX_V4FSID;
1769			break;
1770		case NFSATTRBIT_RDATTRERROR:
1771			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1772			if (nonrefbit)
1773				*tl = txdr_unsigned(NFSERR_MOVED);
1774			else
1775				*tl = 0;
1776			retnum += NFSX_UNSIGNED;
1777			break;
1778		case NFSATTRBIT_FSLOCATIONS:
1779			retnum += nfsm_strtom(nd, "/", 1);
1780			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1781			*tl = txdr_unsigned(refp->nfr_srvcnt);
1782			retnum += NFSX_UNSIGNED;
1783			cp = refp->nfr_srvlist;
1784			for (i = 0; i < refp->nfr_srvcnt; i++) {
1785				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1786				*tl = txdr_unsigned(1);
1787				retnum += NFSX_UNSIGNED;
1788				cp2 = STRCHR(cp, ':');
1789				if (cp2 != NULL)
1790					len = cp2 - cp;
1791				else
1792					len = 1;
1793				retnum += nfsm_strtom(nd, cp, len);
1794				if (cp2 != NULL)
1795					cp = cp2 + 1;
1796				cp2 = STRCHR(cp, ',');
1797				if (cp2 != NULL)
1798					len = cp2 - cp;
1799				else
1800					len = strlen(cp);
1801				retnum += nfsm_strtom(nd, cp, len);
1802				if (cp2 != NULL)
1803					cp = cp2 + 1;
1804			}
1805			break;
1806		case NFSATTRBIT_MOUNTEDONFILEID:
1807			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
1808			*tl++ = 0;
1809			*tl = txdr_unsigned(refp->nfr_dfileno);
1810			retnum += NFSX_HYPER;
1811			break;
1812		default:
1813			printf("EEK! Bad V4 refattr bitpos=%d\n", bitpos);
1814		};
1815	    }
1816	}
1817	*retnump = txdr_unsigned(retnum);
1818	return (retnum + prefixnum);
1819}
1820
1821/*
1822 * Parse a file name out of a request.
1823 */
1824APPLESTATIC int
1825nfsrv_parsename(struct nfsrv_descript *nd, char *bufp, u_long *hashp,
1826    NFSPATHLEN_T *outlenp)
1827{
1828	char *fromcp, *tocp, val = '\0';
1829	mbuf_t md;
1830	int i;
1831	int rem, len, error = 0, pubtype = 0, outlen = 0, percent = 0;
1832	char digit;
1833	u_int32_t *tl;
1834	u_long hash = 0;
1835
1836	if (hashp != NULL)
1837		*hashp = 0;
1838	tocp = bufp;
1839	/*
1840	 * For V4, check for lookup parent.
1841	 * Otherwise, get the component name.
1842	 */
1843	if ((nd->nd_flag & ND_NFSV4) && nd->nd_procnum == NFSV4OP_LOOKUPP) {
1844	    *tocp++ = '.';
1845	    hash += ((u_char)'.');
1846	    *tocp++ = '.';
1847	    hash += ((u_char)'.');
1848	    outlen = 2;
1849	} else {
1850	    /*
1851	     * First, get the name length.
1852	     */
1853	    NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1854	    len = fxdr_unsigned(int, *tl);
1855	    if (len > NFS_MAXNAMLEN) {
1856		nd->nd_repstat = NFSERR_NAMETOL;
1857		error = 0;
1858		goto nfsmout;
1859	    } else if (len <= 0) {
1860		nd->nd_repstat = NFSERR_INVAL;
1861		error = 0;
1862		goto nfsmout;
1863	    }
1864
1865	    /*
1866	     * Now, copy the component name into the buffer.
1867	     */
1868	    fromcp = nd->nd_dpos;
1869	    md = nd->nd_md;
1870	    rem = NFSMTOD(md, caddr_t) + mbuf_len(md) - fromcp;
1871	    for (i = 0; i < len; i++) {
1872		while (rem == 0) {
1873			md = mbuf_next(md);
1874			if (md == NULL) {
1875				error = EBADRPC;
1876				goto nfsmout;
1877			}
1878			fromcp = NFSMTOD(md, caddr_t);
1879			rem = mbuf_len(md);
1880		}
1881		if (*fromcp == '\0') {
1882			nd->nd_repstat = EACCES;
1883			error = 0;
1884			goto nfsmout;
1885		}
1886		/*
1887		 * For lookups on the public filehandle, do some special
1888		 * processing on the name. (The public file handle is the
1889		 * root of the public file system for this server.)
1890		 */
1891		if (nd->nd_flag & ND_PUBLOOKUP) {
1892			/*
1893			 * If the first char is ASCII, it is a canonical
1894			 * path, otherwise it is a native path. (RFC2054
1895			 * doesn't actually state what it is if the first
1896			 * char isn't ASCII or 0x80, so I assume native.)
1897			 * pubtype == 1 -> native path
1898			 * pubtype == 2 -> canonical path
1899			 */
1900			if (i == 0) {
1901				if (*fromcp & 0x80) {
1902					/*
1903					 * Since RFC2054 doesn't indicate
1904					 * that a native path of just 0x80
1905					 * isn't allowed, I'll replace the
1906					 * 0x80 with '/' instead of just
1907					 * throwing it away.
1908					 */
1909					*fromcp = '/';
1910					pubtype = 1;
1911				} else {
1912					pubtype = 2;
1913				}
1914			}
1915			/*
1916			 * '/' only allowed in a native path
1917			 */
1918			if (*fromcp == '/' && pubtype != 1) {
1919				nd->nd_repstat = EACCES;
1920				error = 0;
1921				goto nfsmout;
1922			}
1923
1924			/*
1925			 * For the special case of 2 hex digits after a
1926			 * '%' in an absolute path, calculate the value.
1927			 * percent == 1 -> indicates "get first hex digit"
1928			 * percent == 2 -> indicates "get second hex digit"
1929			 */
1930			if (percent > 0) {
1931				digit = nfsrv_hexdigit(*fromcp, &error);
1932				if (error) {
1933					nd->nd_repstat = EACCES;
1934					error = 0;
1935					goto nfsmout;
1936				}
1937				if (percent == 1) {
1938					val = (digit << 4);
1939					percent = 2;
1940				} else {
1941					val += digit;
1942					percent = 0;
1943					*tocp++ = val;
1944					hash += ((u_char)val);
1945					outlen++;
1946				}
1947			} else {
1948				if (*fromcp == '%' && pubtype == 2) {
1949					/*
1950					 * Must be followed by 2 hex digits
1951					 */
1952					if ((len - i) < 3) {
1953						nd->nd_repstat = EACCES;
1954						error = 0;
1955						goto nfsmout;
1956					}
1957					percent = 1;
1958				} else {
1959					*tocp++ = *fromcp;
1960					hash += ((u_char)*fromcp);
1961					outlen++;
1962				}
1963			}
1964		} else {
1965			/*
1966			 * Normal, non lookup on public, name.
1967			 */
1968			if (*fromcp == '/') {
1969				if (nd->nd_flag & ND_NFSV4)
1970					nd->nd_repstat = NFSERR_BADNAME;
1971				else
1972					nd->nd_repstat = EACCES;
1973				error = 0;
1974				goto nfsmout;
1975			}
1976			hash += ((u_char)*fromcp);
1977			*tocp++ = *fromcp;
1978			outlen++;
1979		}
1980		fromcp++;
1981		rem--;
1982	    }
1983	    nd->nd_md = md;
1984	    nd->nd_dpos = fromcp;
1985	    i = NFSM_RNDUP(len) - len;
1986	    if (i > 0) {
1987		if (rem >= i) {
1988			nd->nd_dpos += i;
1989		} else {
1990			error = nfsm_advance(nd, i, rem);
1991			if (error)
1992				goto nfsmout;
1993		}
1994	    }
1995
1996	    /*
1997	     * For v4, don't allow lookups of '.' or '..' and
1998	     * also check for non-utf8 strings.
1999	     */
2000	    if (nd->nd_flag & ND_NFSV4) {
2001		if ((outlen == 1 && bufp[0] == '.') ||
2002		    (outlen == 2 && bufp[0] == '.' &&
2003		     bufp[1] == '.')) {
2004		    nd->nd_repstat = NFSERR_BADNAME;
2005		    error = 0;
2006		    goto nfsmout;
2007		}
2008		if (disable_checkutf8 == 0 &&
2009		    nfsrv_checkutf8((u_int8_t *)bufp, outlen)) {
2010		    nd->nd_repstat = NFSERR_INVAL;
2011		    error = 0;
2012		    goto nfsmout;
2013		}
2014	    }
2015	}
2016	*tocp = '\0';
2017	*outlenp = (size_t)outlen;
2018	if (hashp != NULL)
2019		*hashp = hash;
2020nfsmout:
2021	NFSEXITCODE2(error, nd);
2022	return (error);
2023}
2024
2025void
2026nfsd_init(void)
2027{
2028	int i;
2029	static int inited = 0;
2030
2031	if (inited)
2032		return;
2033	inited = 1;
2034
2035	/*
2036	 * Initialize client queues. Don't free/reinitialize
2037	 * them when nfsds are restarted.
2038	 */
2039	for (i = 0; i < NFSCLIENTHASHSIZE; i++)
2040		LIST_INIT(&nfsclienthash[i]);
2041	for (i = 0; i < NFSLOCKHASHSIZE; i++)
2042		LIST_INIT(&nfslockhash[i]);
2043	for (i = 0; i < NFSSESSIONHASHSIZE; i++)
2044		LIST_INIT(&nfssessionhash[i].list);
2045
2046	/* and the v2 pubfh should be all zeros */
2047	NFSBZERO(nfs_v2pubfh, NFSX_V2FH);
2048}
2049
2050/*
2051 * Check the v4 root exports.
2052 * Return 0 if ok, 1 otherwise.
2053 */
2054int
2055nfsd_checkrootexp(struct nfsrv_descript *nd)
2056{
2057
2058	if ((nd->nd_flag & (ND_GSS | ND_EXAUTHSYS)) == ND_EXAUTHSYS)
2059		return (0);
2060	if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) ==
2061	    (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY))
2062		return (0);
2063	if ((nd->nd_flag & (ND_GSSPRIVACY | ND_EXGSSPRIVACY)) ==
2064	    (ND_GSSPRIVACY | ND_EXGSSPRIVACY))
2065		return (0);
2066	if ((nd->nd_flag & (ND_GSS | ND_GSSINTEGRITY | ND_GSSPRIVACY |
2067	     ND_EXGSS)) == (ND_GSS | ND_EXGSS))
2068		return (0);
2069	return (1);
2070}
2071
2072/*
2073 * Parse the first part of an NFSv4 compound to find out what the minor
2074 * version# is.
2075 */
2076void
2077nfsd_getminorvers(struct nfsrv_descript *nd, u_char *tag, u_char **tagstrp,
2078    int *taglenp, u_int32_t *minversp)
2079{
2080	uint32_t *tl;
2081	int error = 0, taglen = -1;
2082	u_char *tagstr = NULL;
2083
2084	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2085	taglen = fxdr_unsigned(int, *tl);
2086	if (taglen < 0 || taglen > NFSV4_OPAQUELIMIT) {
2087		error = EBADRPC;
2088		goto nfsmout;
2089	}
2090	if (taglen <= NFSV4_SMALLSTR)
2091		tagstr = tag;
2092	else
2093		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
2094	error = nfsrv_mtostr(nd, tagstr, taglen);
2095	if (error != 0)
2096		goto nfsmout;
2097	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2098	*minversp = fxdr_unsigned(u_int32_t, *tl);
2099	*tagstrp = tagstr;
2100	if (*minversp == NFSV41_MINORVERSION)
2101		nd->nd_flag |= ND_NFSV41;
2102nfsmout:
2103	if (error != 0) {
2104		if (tagstr != NULL && taglen > NFSV4_SMALLSTR)
2105			free(tagstr, M_TEMP);
2106		taglen = -1;
2107	}
2108	*taglenp = taglen;
2109}
2110
2111