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