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