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