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