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