]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/fs/nfsserver/nfs_nfsdsubs.c
MFC r368207,368607:
[FreeBSD/stable/10.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         NFSERR_WRONGSEC,
1148         0,
1149 };
1150
1151 static short nfsv4err_setclientidconfirm[] = {
1152         NFSERR_SERVERFAULT,
1153         NFSERR_BADXDR,
1154         NFSERR_CLIDINUSE,
1155         NFSERR_RESOURCE,
1156         NFSERR_SERVERFAULT,
1157         NFSERR_STALECLIENTID,
1158         0,
1159 };
1160
1161 static short nfsv4err_verify[] = {
1162         NFSERR_SERVERFAULT,
1163         NFSERR_ACCES,
1164         NFSERR_ATTRNOTSUPP,
1165         NFSERR_BADCHAR,
1166         NFSERR_BADHANDLE,
1167         NFSERR_BADXDR,
1168         NFSERR_DELAY,
1169         NFSERR_FHEXPIRED,
1170         NFSERR_INVAL,
1171         NFSERR_MOVED,
1172         NFSERR_NOFILEHANDLE,
1173         NFSERR_NOTSAME,
1174         NFSERR_RESOURCE,
1175         NFSERR_SERVERFAULT,
1176         NFSERR_STALE,
1177         0,
1178 };
1179
1180 static short nfsv4err_write[] = {
1181         NFSERR_IO,
1182         NFSERR_ACCES,
1183         NFSERR_ADMINREVOKED,
1184         NFSERR_BADHANDLE,
1185         NFSERR_BADSTATEID,
1186         NFSERR_BADXDR,
1187         NFSERR_DELAY,
1188         NFSERR_DQUOT,
1189         NFSERR_EXPIRED,
1190         NFSERR_FBIG,
1191         NFSERR_FHEXPIRED,
1192         NFSERR_GRACE,
1193         NFSERR_INVAL,
1194         NFSERR_IO,
1195         NFSERR_ISDIR,
1196         NFSERR_LEASEMOVED,
1197         NFSERR_LOCKED,
1198         NFSERR_MOVED,
1199         NFSERR_NOFILEHANDLE,
1200         NFSERR_NOSPC,
1201         NFSERR_NXIO,
1202         NFSERR_OLDSTATEID,
1203         NFSERR_OPENMODE,
1204         NFSERR_RESOURCE,
1205         NFSERR_ROFS,
1206         NFSERR_SERVERFAULT,
1207         NFSERR_STALE,
1208         NFSERR_STALESTATEID,
1209         0,
1210 };
1211
1212 static short nfsv4err_releaselockowner[] = {
1213         NFSERR_SERVERFAULT,
1214         NFSERR_ADMINREVOKED,
1215         NFSERR_BADXDR,
1216         NFSERR_EXPIRED,
1217         NFSERR_LEASEMOVED,
1218         NFSERR_LOCKSHELD,
1219         NFSERR_RESOURCE,
1220         NFSERR_SERVERFAULT,
1221         NFSERR_STALECLIENTID,
1222         0,
1223 };
1224
1225 static short *nfsrv_v4errmap[] = {
1226         nfsv4err_null,
1227         nfsv4err_null,
1228         nfsv4err_null,
1229         nfsv4err_access,
1230         nfsv4err_close,
1231         nfsv4err_commit,
1232         nfsv4err_create,
1233         nfsv4err_delegpurge,
1234         nfsv4err_delegreturn,
1235         nfsv4err_getattr,
1236         nfsv4err_getfh,
1237         nfsv4err_link,
1238         nfsv4err_lock,
1239         nfsv4err_lockt,
1240         nfsv4err_locku,
1241         nfsv4err_lookup,
1242         nfsv4err_lookupp,
1243         nfsv4err_nverify,
1244         nfsv4err_open,
1245         nfsv4err_openattr,
1246         nfsv4err_openconfirm,
1247         nfsv4err_opendowngrade,
1248         nfsv4err_putfh,
1249         nfsv4err_putpubfh,
1250         nfsv4err_putrootfh,
1251         nfsv4err_read,
1252         nfsv4err_readdir,
1253         nfsv4err_readlink,
1254         nfsv4err_remove,
1255         nfsv4err_rename,
1256         nfsv4err_renew,
1257         nfsv4err_restorefh,
1258         nfsv4err_savefh,
1259         nfsv4err_secinfo,
1260         nfsv4err_setattr,
1261         nfsv4err_setclientid,
1262         nfsv4err_setclientidconfirm,
1263         nfsv4err_verify,
1264         nfsv4err_write,
1265         nfsv4err_releaselockowner,
1266 };
1267
1268 /*
1269  * A fiddled version of m_adj() that ensures null fill to a long
1270  * boundary and only trims off the back end
1271  */
1272 APPLESTATIC void
1273 nfsrv_adj(mbuf_t mp, int len, int nul)
1274 {
1275         mbuf_t m;
1276         int count, i;
1277         char *cp;
1278
1279         /*
1280          * Trim from tail.  Scan the mbuf chain,
1281          * calculating its length and finding the last mbuf.
1282          * If the adjustment only affects this mbuf, then just
1283          * adjust and return.  Otherwise, rescan and truncate
1284          * after the remaining size.
1285          */
1286         count = 0;
1287         m = mp;
1288         for (;;) {
1289                 count += mbuf_len(m);
1290                 if (mbuf_next(m) == NULL)
1291                         break;
1292                 m = mbuf_next(m);
1293         }
1294         if (mbuf_len(m) > len) {
1295                 mbuf_setlen(m, mbuf_len(m) - len);
1296                 if (nul > 0) {
1297                         cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1298                         for (i = 0; i < nul; i++)
1299                                 *cp++ = '\0';
1300                 }
1301                 return;
1302         }
1303         count -= len;
1304         if (count < 0)
1305                 count = 0;
1306         /*
1307          * Correct length for chain is "count".
1308          * Find the mbuf with last data, adjust its length,
1309          * and toss data from remaining mbufs on chain.
1310          */
1311         for (m = mp; m; m = mbuf_next(m)) {
1312                 if (mbuf_len(m) >= count) {
1313                         mbuf_setlen(m, count);
1314                         if (nul > 0) {
1315                                 cp = NFSMTOD(m, caddr_t) + mbuf_len(m) - nul;
1316                                 for (i = 0; i < nul; i++)
1317                                         *cp++ = '\0';
1318                         }
1319                         break;
1320                 }
1321                 count -= mbuf_len(m);
1322         }
1323         for (m = mbuf_next(m); m; m = mbuf_next(m))
1324                 mbuf_setlen(m, 0);
1325 }
1326
1327 /*
1328  * Make these functions instead of macros, so that the kernel text size
1329  * doesn't get too big...
1330  */
1331 APPLESTATIC void
1332 nfsrv_wcc(struct nfsrv_descript *nd, int before_ret,
1333     struct nfsvattr *before_nvap, int after_ret, struct nfsvattr *after_nvap)
1334 {
1335         u_int32_t *tl;
1336
1337         if (before_ret) {
1338                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1339                 *tl = newnfs_false;
1340         } else {
1341                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1342                 *tl++ = newnfs_true;
1343                 txdr_hyper(before_nvap->na_size, tl);
1344                 tl += 2;
1345                 txdr_nfsv3time(&(before_nvap->na_mtime), tl);
1346                 tl += 2;
1347                 txdr_nfsv3time(&(before_nvap->na_ctime), tl);
1348         }
1349         nfsrv_postopattr(nd, after_ret, after_nvap);
1350 }
1351
1352 APPLESTATIC void
1353 nfsrv_postopattr(struct nfsrv_descript *nd, int after_ret,
1354     struct nfsvattr *after_nvap)
1355 {
1356         u_int32_t *tl;
1357
1358         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1359         if (after_ret)
1360                 *tl = newnfs_false;
1361         else {
1362                 *tl = newnfs_true;
1363                 nfsrv_fillattr(nd, after_nvap);
1364         }
1365 }
1366
1367 /*
1368  * Fill in file attributes for V2 and 3. For V4, call a separate
1369  * routine that sifts through all the attribute bits.
1370  */
1371 APPLESTATIC void
1372 nfsrv_fillattr(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1373 {
1374         struct nfs_fattr *fp;
1375         int fattr_size;
1376
1377         /*
1378          * Build space for the attribute structure.
1379          */
1380         if (nd->nd_flag & ND_NFSV3)
1381                 fattr_size = NFSX_V3FATTR;
1382         else
1383                 fattr_size = NFSX_V2FATTR;
1384         NFSM_BUILD(fp, struct nfs_fattr *, fattr_size);
1385
1386         /*
1387          * Now just fill it all in.
1388          */
1389         fp->fa_nlink = txdr_unsigned(nvap->na_nlink);
1390         fp->fa_uid = txdr_unsigned(nvap->na_uid);
1391         fp->fa_gid = txdr_unsigned(nvap->na_gid);
1392         if (nd->nd_flag & ND_NFSV3) {
1393                 fp->fa_type = vtonfsv34_type(nvap->na_type);
1394                 fp->fa_mode = vtonfsv34_mode(nvap->na_mode);
1395                 txdr_hyper(nvap->na_size, &fp->fa3_size);
1396                 txdr_hyper(nvap->na_bytes, &fp->fa3_used);
1397                 fp->fa3_rdev.specdata1 = txdr_unsigned(NFSMAJOR(nvap->na_rdev));
1398                 fp->fa3_rdev.specdata2 = txdr_unsigned(NFSMINOR(nvap->na_rdev));
1399                 fp->fa3_fsid.nfsuquad[0] = 0;
1400                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(nvap->na_fsid);
1401                 fp->fa3_fileid.nfsuquad[0] = 0;
1402                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(nvap->na_fileid);
1403                 txdr_nfsv3time(&nvap->na_atime, &fp->fa3_atime);
1404                 txdr_nfsv3time(&nvap->na_mtime, &fp->fa3_mtime);
1405                 txdr_nfsv3time(&nvap->na_ctime, &fp->fa3_ctime);
1406         } else {
1407                 fp->fa_type = vtonfsv2_type(nvap->na_type);
1408                 fp->fa_mode = vtonfsv2_mode(nvap->na_type, nvap->na_mode);
1409                 fp->fa2_size = txdr_unsigned(nvap->na_size);
1410                 fp->fa2_blocksize = txdr_unsigned(nvap->na_blocksize);
1411                 if (nvap->na_type == VFIFO)
1412                         fp->fa2_rdev = 0xffffffff;
1413                 else
1414                         fp->fa2_rdev = txdr_unsigned(nvap->na_rdev);
1415                 fp->fa2_blocks = txdr_unsigned(nvap->na_bytes / NFS_FABLKSIZE);
1416                 fp->fa2_fsid = txdr_unsigned(nvap->na_fsid);
1417                 fp->fa2_fileid = txdr_unsigned(nvap->na_fileid);
1418                 txdr_nfsv2time(&nvap->na_atime, &fp->fa2_atime);
1419                 txdr_nfsv2time(&nvap->na_mtime, &fp->fa2_mtime);
1420                 txdr_nfsv2time(&nvap->na_ctime, &fp->fa2_ctime);
1421         }
1422 }
1423
1424 /*
1425  * This function gets a file handle out of an mbuf list.
1426  * It returns 0 for success, EBADRPC otherwise.
1427  * If sets the third flagp argument to 1 if the file handle is
1428  * the public file handle.
1429  * For NFSv4, if the length is incorrect, set nd_repstat == NFSERR_BADHANDLE
1430  */
1431 APPLESTATIC int
1432 nfsrv_mtofh(struct nfsrv_descript *nd, struct nfsrvfh *fhp)
1433 {
1434         u_int32_t *tl;
1435         int error = 0, len, copylen;
1436
1437         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1438                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1439                 len = fxdr_unsigned(int, *tl);
1440                 if (len == 0 && nfs_pubfhset && (nd->nd_flag & ND_NFSV3) &&
1441                     nd->nd_procnum == NFSPROC_LOOKUP) {
1442                         nd->nd_flag |= ND_PUBLOOKUP;
1443                         goto nfsmout;
1444                 }
1445                 if (len < NFSRV_MINFH || len > NFSRV_MAXFH) {
1446                         if (nd->nd_flag & ND_NFSV4) {
1447                             if (len > 0 && len <= NFSX_V4FHMAX) {
1448                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1449                                 if (error)
1450                                         goto nfsmout;
1451                                 nd->nd_repstat = NFSERR_BADHANDLE;
1452                                 goto nfsmout;
1453                             } else {
1454                                     error = EBADRPC;
1455                                     goto nfsmout;
1456                             }
1457                         } else {
1458                                 error = EBADRPC;
1459                                 goto nfsmout;
1460                         }
1461                 }
1462                 copylen = len;
1463         } else {
1464                 /*
1465                  * For NFSv2, the file handle is always 32 bytes on the
1466                  * wire, but this server only cares about the first
1467                  * NFSRV_MAXFH bytes.
1468                  */
1469                 len = NFSX_V2FH;
1470                 copylen = NFSRV_MAXFH;
1471         }
1472         NFSM_DISSECT(tl, u_int32_t *, len);
1473         if ((nd->nd_flag & ND_NFSV2) && nfs_pubfhset &&
1474             nd->nd_procnum == NFSPROC_LOOKUP &&
1475             !NFSBCMP((caddr_t)tl, nfs_v2pubfh, NFSX_V2FH)) {
1476                 nd->nd_flag |= ND_PUBLOOKUP;
1477                 goto nfsmout;
1478         }
1479         NFSBCOPY(tl, (caddr_t)fhp->nfsrvfh_data, copylen);
1480         fhp->nfsrvfh_len = copylen;
1481 nfsmout:
1482         NFSEXITCODE2(error, nd);
1483         return (error);
1484 }
1485
1486 /*
1487  * Map errnos to NFS error numbers. For Version 3 and 4 also filter out error
1488  * numbers not specified for the associated procedure.
1489  * NFSPROC_NOOP is a special case, where the high order bits of nd_repstat
1490  * should be cleared. NFSPROC_NOOP is used to return errors when a valid
1491  * RPC procedure is not involved.
1492  * Returns the error number in XDR.
1493  */
1494 APPLESTATIC int
1495 nfsd_errmap(struct nfsrv_descript *nd)
1496 {
1497         short *defaulterrp, *errp;
1498
1499         if (!nd->nd_repstat)
1500                 return (0);
1501         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1502                 if (nd->nd_procnum == NFSPROC_NOOP)
1503                         return (txdr_unsigned(nd->nd_repstat & 0xffff));
1504                 if (nd->nd_flag & ND_NFSV3)
1505                     errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1506                 else if (nd->nd_repstat == EBADRPC)
1507                         return (txdr_unsigned(NFSERR_BADXDR));
1508                 else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
1509                          nd->nd_repstat == NFSERR_OPILLEGAL)
1510                         return (txdr_unsigned(nd->nd_repstat));
1511                 else if ((nd->nd_flag & ND_NFSV41) != 0) {
1512                         if (nd->nd_repstat == EOPNOTSUPP)
1513                                 nd->nd_repstat = NFSERR_NOTSUPP;
1514                         nd->nd_repstat = nfsrv_isannfserr(nd->nd_repstat);
1515                         return (txdr_unsigned(nd->nd_repstat));
1516                 } else
1517                     errp = defaulterrp = nfsrv_v4errmap[nd->nd_procnum];
1518                 while (*++errp)
1519                         if (*errp == nd->nd_repstat)
1520                                 return (txdr_unsigned(nd->nd_repstat));
1521                 return (txdr_unsigned(*defaulterrp));
1522         }
1523         if (nd->nd_repstat <= NFSERR_REMOTE)
1524                 return (txdr_unsigned(nfsrv_v2errmap[nd->nd_repstat - 1]));
1525         return (txdr_unsigned(NFSERR_IO));
1526 }
1527
1528 /*
1529  * Check to see if the error is a valid NFS one. If not, replace it with
1530  * NFSERR_IO.
1531  */
1532 static u_int32_t
1533 nfsrv_isannfserr(u_int32_t errval)
1534 {
1535
1536         if (errval == NFSERR_OK)
1537                 return (errval);
1538         if (errval >= NFSERR_BADHANDLE && errval <= NFSERR_DELEGREVOKED)
1539                 return (errval);
1540         if (errval > 0 && errval <= NFSERR_REMOTE)
1541                 return (nfsrv_v2errmap[errval - 1]);
1542         return (NFSERR_IO);
1543 }
1544
1545 /*
1546  * Check to see if setting a uid/gid is permitted when creating a new
1547  * file object. (Called when uid and/or gid is specified in the
1548  * settable attributes for V4.
1549  */
1550 APPLESTATIC int
1551 nfsrv_checkuidgid(struct nfsrv_descript *nd, struct nfsvattr *nvap)
1552 {
1553         int error = 0;
1554
1555         /*
1556          * If not setting either uid nor gid, it's OK.
1557          */
1558         if (NFSVNO_NOTSETUID(nvap) && NFSVNO_NOTSETGID(nvap))
1559                 goto out;
1560         if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid == nfsrv_defaultuid &&
1561            enable_nobodycheck == 1)
1562             || (NFSVNO_ISSETGID(nvap) && nvap->na_gid == nfsrv_defaultgid &&
1563            enable_nogroupcheck == 1)) {
1564                 error = NFSERR_BADOWNER;
1565                 goto out;
1566         }
1567         if (nd->nd_cred->cr_uid == 0)
1568                 goto out;
1569         if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid != nd->nd_cred->cr_uid) ||
1570             (NFSVNO_ISSETGID(nvap) && nvap->na_gid != nd->nd_cred->cr_gid &&
1571             !groupmember(nvap->na_gid, nd->nd_cred)))
1572                 error = NFSERR_PERM;
1573
1574 out:
1575         NFSEXITCODE2(error, nd);
1576         return (error);
1577 }
1578
1579 /*
1580  * and this routine fixes up the settable attributes for V4 if allowed
1581  * by nfsrv_checkuidgid().
1582  */
1583 APPLESTATIC void
1584 nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
1585     struct nfsvattr *nvap, NFSACL_T *aclp, NFSPROC_T *p, nfsattrbit_t *attrbitp,
1586     struct nfsexstuff *exp)
1587 {
1588         int change = 0;
1589         struct nfsvattr nva;
1590         uid_t tuid;
1591         int error;
1592         nfsattrbit_t nattrbits;
1593
1594         /*
1595          * Maybe this should be done for V2 and 3 but it never has been
1596          * and nobody seems to be upset, so I think it's best not to change
1597          * the V2 and 3 semantics.
1598          */
1599         if ((nd->nd_flag & ND_NFSV4) == 0)
1600                 goto out;
1601         NFSVNO_ATTRINIT(&nva);
1602         NFSZERO_ATTRBIT(&nattrbits);
1603         tuid = nd->nd_cred->cr_uid;
1604         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) &&
1605             NFSVNO_ISSETUID(nvap) &&
1606             nvap->na_uid != nd->nd_cred->cr_uid) {
1607                 if (nd->nd_cred->cr_uid == 0) {
1608                         nva.na_uid = nvap->na_uid;
1609                         change++;
1610                         NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNER);
1611                 } else {
1612                         NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNER);
1613                 }
1614         }
1615         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEACCESSSET) &&
1616             NFSVNO_ISSETATIME(nvap)) {
1617                 nva.na_atime = nvap->na_atime;
1618                 change++;
1619                 NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEACCESSSET);
1620         }
1621         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_TIMEMODIFYSET) &&
1622             NFSVNO_ISSETMTIME(nvap)) {
1623                 nva.na_mtime = nvap->na_mtime;
1624                 change++;
1625                 NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_TIMEMODIFYSET);
1626         }
1627         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) &&
1628             NFSVNO_ISSETGID(nvap)) {
1629                 if (nvap->na_gid == nd->nd_cred->cr_gid ||
1630                     groupmember(nvap->na_gid, nd->nd_cred)) {
1631                         nd->nd_cred->cr_uid = 0;
1632                         nva.na_gid = nvap->na_gid;
1633                         change++;
1634                         NFSSETBIT_ATTRBIT(&nattrbits, NFSATTRBIT_OWNERGROUP);
1635                 } else {
1636                         NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP);
1637                 }
1638         }
1639         if (change) {
1640                 error = nfsvno_setattr(vp, &nva, nd->nd_cred, p, exp);
1641                 if (error) {
1642                         NFSCLRALL_ATTRBIT(attrbitp, &nattrbits);
1643                 }
1644         }
1645         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE) &&
1646             NFSVNO_ISSETSIZE(nvap) && nvap->na_size != (u_quad_t)0) {
1647                 NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_SIZE);
1648         }
1649 #ifdef NFS4_ACL_EXTATTR_NAME
1650         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL) &&
1651             nfsrv_useacl != 0 && aclp != NULL) {
1652                 if (aclp->acl_cnt > 0) {
1653                         error = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
1654                         if (error) {
1655                                 NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1656                         }
1657                 }
1658         } else
1659 #endif
1660         NFSCLRBIT_ATTRBIT(attrbitp, NFSATTRBIT_ACL);
1661         nd->nd_cred->cr_uid = tuid;
1662
1663 out:
1664         NFSEXITCODE2(0, nd);
1665 }
1666
1667 /*
1668  * Translate an ASCII hex digit to it's binary value. Return -1 if the
1669  * char isn't a hex digit.
1670  */
1671 static char
1672 nfsrv_hexdigit(char c, int *err)
1673 {
1674
1675         *err = 0;
1676         if (c >= '0' && c <= '9')
1677                 return (c - '0');
1678         if (c >= 'a' && c <= 'f')
1679                 return (c - 'a' + ((char)10));
1680         if (c >= 'A' && c <= 'F')
1681                 return (c - 'A' + ((char)10));
1682         /* Not valid ! */
1683         *err = 1;
1684         return (1);     /* BOGUS */
1685 }
1686
1687 /*
1688  * Check to see if NFSERR_MOVED can be returned for this op. Return 1 iff
1689  * it can be.
1690  */
1691 APPLESTATIC int
1692 nfsrv_errmoved(int op)
1693 {
1694         short *errp;
1695
1696         errp = nfsrv_v4errmap[op];
1697         while (*errp != 0) {
1698                 if (*errp == NFSERR_MOVED)
1699                         return (1);
1700                 errp++;
1701         }
1702         return (0);
1703 }
1704
1705 /*
1706  * Fill in attributes for a Referral.
1707  * (Return the number of bytes of XDR created.)
1708  */
1709 APPLESTATIC int
1710 nfsrv_putreferralattr(struct nfsrv_descript *nd, nfsattrbit_t *retbitp,
1711     struct nfsreferral *refp, int getattr, int *reterrp)
1712 {
1713         u_int32_t *tl, *retnump;
1714         u_char *cp, *cp2;
1715         int prefixnum, retnum = 0, i, len, bitpos, rderrbit = 0, nonrefbit = 0;
1716         int fslocationsbit = 0;
1717         nfsattrbit_t tmpbits, refbits;
1718
1719         NFSREFERRAL_ATTRBIT(&refbits);
1720         if (getattr)
1721                 NFSCLRBIT_ATTRBIT(&refbits, NFSATTRBIT_RDATTRERROR);
1722         else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_RDATTRERROR))
1723                 rderrbit = 1;
1724         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_FSLOCATIONS))
1725                 fslocationsbit = 1;
1726
1727         /*
1728          * Check for the case where unsupported referral attributes are
1729          * requested.
1730          */
1731         NFSSET_ATTRBIT(&tmpbits, retbitp);
1732         NFSCLRALL_ATTRBIT(&tmpbits, &refbits);
1733         if (NFSNONZERO_ATTRBIT(&tmpbits))
1734                 nonrefbit = 1;
1735
1736         if (nonrefbit && !fslocationsbit && (getattr || !rderrbit)) {
1737                 *reterrp = NFSERR_MOVED;
1738                 return (0);
1739         }
1740
1741         /*
1742          * Now we can fill in the attributes.
1743          */
1744         NFSSET_ATTRBIT(&tmpbits, retbitp);
1745         NFSCLRNOT_ATTRBIT(&tmpbits, &refbits);
1746
1747         /*
1748          * Put out the attribute bitmap for the ones being filled in
1749          * and get the field for the number of attributes returned.
1750          */
1751         prefixnum = nfsrv_putattrbit(nd, &tmpbits);
1752         NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1753         prefixnum += NFSX_UNSIGNED;
1754
1755         /*
1756          * Now, loop around filling in the attributes for each bit set.
1757          */
1758         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1759             if (NFSISSET_ATTRBIT(&tmpbits, bitpos)) {
1760                 switch (bitpos) {
1761                 case NFSATTRBIT_TYPE:
1762                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1763                         *tl = txdr_unsigned(NFDIR);
1764                         retnum += NFSX_UNSIGNED;
1765                         break;
1766                 case NFSATTRBIT_FSID:
1767                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
1768                         *tl++ = 0;
1769                         *tl++ = txdr_unsigned(NFSV4ROOT_FSID0);
1770                         *tl++ = 0;
1771                         *tl = txdr_unsigned(NFSV4ROOT_REFERRAL);
1772                         retnum += NFSX_V4FSID;
1773                         break;
1774                 case NFSATTRBIT_RDATTRERROR:
1775                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1776                         if (nonrefbit)
1777                                 *tl = txdr_unsigned(NFSERR_MOVED);
1778                         else
1779                                 *tl = 0;
1780                         retnum += NFSX_UNSIGNED;
1781                         break;
1782                 case NFSATTRBIT_FSLOCATIONS:
1783                         retnum += nfsm_strtom(nd, "/", 1);
1784                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1785                         *tl = txdr_unsigned(refp->nfr_srvcnt);
1786                         retnum += NFSX_UNSIGNED;
1787                         cp = refp->nfr_srvlist;
1788                         for (i = 0; i < refp->nfr_srvcnt; i++) {
1789                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1790                                 *tl = txdr_unsigned(1);
1791                                 retnum += NFSX_UNSIGNED;
1792                                 cp2 = STRCHR(cp, ':');
1793                                 if (cp2 != NULL)
1794                                         len = cp2 - cp;
1795                                 else
1796                                         len = 1;
1797                                 retnum += nfsm_strtom(nd, cp, len);
1798                                 if (cp2 != NULL)
1799                                         cp = cp2 + 1;
1800                                 cp2 = STRCHR(cp, ',');
1801                                 if (cp2 != NULL)
1802                                         len = cp2 - cp;
1803                                 else
1804                                         len = strlen(cp);
1805                                 retnum += nfsm_strtom(nd, cp, len);
1806                                 if (cp2 != NULL)
1807                                         cp = cp2 + 1;
1808                         }
1809                         break;
1810                 case NFSATTRBIT_MOUNTEDONFILEID:
1811                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
1812                         *tl++ = 0;
1813                         *tl = txdr_unsigned(refp->nfr_dfileno);
1814                         retnum += NFSX_HYPER;
1815                         break;
1816                 default:
1817                         printf("EEK! Bad V4 refattr bitpos=%d\n", bitpos);
1818                 };
1819             }
1820         }
1821         *retnump = txdr_unsigned(retnum);
1822         return (retnum + prefixnum);
1823 }
1824
1825 /*
1826  * Parse a file name out of a request.
1827  */
1828 APPLESTATIC int
1829 nfsrv_parsename(struct nfsrv_descript *nd, char *bufp, u_long *hashp,
1830     NFSPATHLEN_T *outlenp)
1831 {
1832         char *fromcp, *tocp, val = '\0';
1833         mbuf_t md;
1834         int i;
1835         int rem, len, error = 0, pubtype = 0, outlen = 0, percent = 0;
1836         char digit;
1837         u_int32_t *tl;
1838         u_long hash = 0;
1839
1840         if (hashp != NULL)
1841                 *hashp = 0;
1842         tocp = bufp;
1843         /*
1844          * For V4, check for lookup parent.
1845          * Otherwise, get the component name.
1846          */
1847         if ((nd->nd_flag & ND_NFSV4) && nd->nd_procnum == NFSV4OP_LOOKUPP) {
1848             *tocp++ = '.';
1849             hash += ((u_char)'.');
1850             *tocp++ = '.';
1851             hash += ((u_char)'.');
1852             outlen = 2;
1853         } else {
1854             /*
1855              * First, get the name length.
1856              */
1857             NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1858             len = fxdr_unsigned(int, *tl);
1859             if (len > NFS_MAXNAMLEN) {
1860                 nd->nd_repstat = NFSERR_NAMETOL;
1861                 error = 0;
1862                 goto nfsmout;
1863             } else if (len <= 0) {
1864                 nd->nd_repstat = NFSERR_INVAL;
1865                 error = 0;
1866                 goto nfsmout;
1867             }
1868
1869             /*
1870              * Now, copy the component name into the buffer.
1871              */
1872             fromcp = nd->nd_dpos;
1873             md = nd->nd_md;
1874             rem = NFSMTOD(md, caddr_t) + mbuf_len(md) - fromcp;
1875             for (i = 0; i < len; i++) {
1876                 while (rem == 0) {
1877                         md = mbuf_next(md);
1878                         if (md == NULL) {
1879                                 error = EBADRPC;
1880                                 goto nfsmout;
1881                         }
1882                         fromcp = NFSMTOD(md, caddr_t);
1883                         rem = mbuf_len(md);
1884                 }
1885                 if (*fromcp == '\0') {
1886                         nd->nd_repstat = EACCES;
1887                         error = 0;
1888                         goto nfsmout;
1889                 }
1890                 /*
1891                  * For lookups on the public filehandle, do some special
1892                  * processing on the name. (The public file handle is the
1893                  * root of the public file system for this server.)
1894                  */
1895                 if (nd->nd_flag & ND_PUBLOOKUP) {
1896                         /*
1897                          * If the first char is ASCII, it is a canonical
1898                          * path, otherwise it is a native path. (RFC2054
1899                          * doesn't actually state what it is if the first
1900                          * char isn't ASCII or 0x80, so I assume native.)
1901                          * pubtype == 1 -> native path
1902                          * pubtype == 2 -> canonical path
1903                          */
1904                         if (i == 0) {
1905                                 if (*fromcp & 0x80) {
1906                                         /*
1907                                          * Since RFC2054 doesn't indicate
1908                                          * that a native path of just 0x80
1909                                          * isn't allowed, I'll replace the
1910                                          * 0x80 with '/' instead of just
1911                                          * throwing it away.
1912                                          */
1913                                         *fromcp = '/';
1914                                         pubtype = 1;
1915                                 } else {
1916                                         pubtype = 2;
1917                                 }
1918                         }
1919                         /*
1920                          * '/' only allowed in a native path
1921                          */
1922                         if (*fromcp == '/' && pubtype != 1) {
1923                                 nd->nd_repstat = EACCES;
1924                                 error = 0;
1925                                 goto nfsmout;
1926                         }
1927
1928                         /*
1929                          * For the special case of 2 hex digits after a
1930                          * '%' in an absolute path, calculate the value.
1931                          * percent == 1 -> indicates "get first hex digit"
1932                          * percent == 2 -> indicates "get second hex digit"
1933                          */
1934                         if (percent > 0) {
1935                                 digit = nfsrv_hexdigit(*fromcp, &error);
1936                                 if (error) {
1937                                         nd->nd_repstat = EACCES;
1938                                         error = 0;
1939                                         goto nfsmout;
1940                                 }
1941                                 if (percent == 1) {
1942                                         val = (digit << 4);
1943                                         percent = 2;
1944                                 } else {
1945                                         val += digit;
1946                                         percent = 0;
1947                                         *tocp++ = val;
1948                                         hash += ((u_char)val);
1949                                         outlen++;
1950                                 }
1951                         } else {
1952                                 if (*fromcp == '%' && pubtype == 2) {
1953                                         /*
1954                                          * Must be followed by 2 hex digits
1955                                          */
1956                                         if ((len - i) < 3) {
1957                                                 nd->nd_repstat = EACCES;
1958                                                 error = 0;
1959                                                 goto nfsmout;
1960                                         }
1961                                         percent = 1;
1962                                 } else {
1963                                         *tocp++ = *fromcp;
1964                                         hash += ((u_char)*fromcp);
1965                                         outlen++;
1966                                 }
1967                         }
1968                 } else {
1969                         /*
1970                          * Normal, non lookup on public, name.
1971                          */
1972                         if (*fromcp == '/') {
1973                                 if (nd->nd_flag & ND_NFSV4)
1974                                         nd->nd_repstat = NFSERR_BADNAME;
1975                                 else
1976                                         nd->nd_repstat = EACCES;
1977                                 error = 0;
1978                                 goto nfsmout;
1979                         }
1980                         hash += ((u_char)*fromcp);
1981                         *tocp++ = *fromcp;
1982                         outlen++;
1983                 }
1984                 fromcp++;
1985                 rem--;
1986             }
1987             nd->nd_md = md;
1988             nd->nd_dpos = fromcp;
1989             i = NFSM_RNDUP(len) - len;
1990             if (i > 0) {
1991                 if (rem >= i) {
1992                         nd->nd_dpos += i;
1993                 } else {
1994                         error = nfsm_advance(nd, i, rem);
1995                         if (error)
1996                                 goto nfsmout;
1997                 }
1998             }
1999
2000             /*
2001              * For v4, don't allow lookups of '.' or '..' and
2002              * also check for non-utf8 strings.
2003              */
2004             if (nd->nd_flag & ND_NFSV4) {
2005                 if ((outlen == 1 && bufp[0] == '.') ||
2006                     (outlen == 2 && bufp[0] == '.' &&
2007                      bufp[1] == '.')) {
2008                     nd->nd_repstat = NFSERR_BADNAME;
2009                     error = 0;
2010                     goto nfsmout;
2011                 }
2012                 if (disable_checkutf8 == 0 &&
2013                     nfsrv_checkutf8((u_int8_t *)bufp, outlen)) {
2014                     nd->nd_repstat = NFSERR_INVAL;
2015                     error = 0;
2016                     goto nfsmout;
2017                 }
2018             }
2019         }
2020         *tocp = '\0';
2021         *outlenp = (size_t)outlen;
2022         if (hashp != NULL)
2023                 *hashp = hash;
2024 nfsmout:
2025         NFSEXITCODE2(error, nd);
2026         return (error);
2027 }
2028
2029 void
2030 nfsd_init(void)
2031 {
2032         int i;
2033         static int inited = 0;
2034
2035         if (inited)
2036                 return;
2037         inited = 1;
2038
2039         /*
2040          * Initialize client queues. Don't free/reinitialize
2041          * them when nfsds are restarted.
2042          */
2043         nfsclienthash = malloc(sizeof(struct nfsclienthashhead) *
2044             nfsrv_clienthashsize, M_NFSDCLIENT, M_WAITOK | M_ZERO);
2045         for (i = 0; i < nfsrv_clienthashsize; i++)
2046                 LIST_INIT(&nfsclienthash[i]);
2047         nfslockhash = malloc(sizeof(struct nfslockhashhead) *
2048             nfsrv_lockhashsize, M_NFSDLOCKFILE, M_WAITOK | M_ZERO);
2049         for (i = 0; i < nfsrv_lockhashsize; i++)
2050                 LIST_INIT(&nfslockhash[i]);
2051         nfssessionhash = malloc(sizeof(struct nfssessionhash) *
2052             nfsrv_sessionhashsize, M_NFSDSESSION, M_WAITOK | M_ZERO);
2053         for (i = 0; i < nfsrv_sessionhashsize; i++) {
2054                 mtx_init(&nfssessionhash[i].mtx, "nfssm", NULL, MTX_DEF);
2055                 LIST_INIT(&nfssessionhash[i].list);
2056         }
2057
2058         /* and the v2 pubfh should be all zeros */
2059         NFSBZERO(nfs_v2pubfh, NFSX_V2FH);
2060 }
2061
2062 /*
2063  * Check the v4 root exports.
2064  * Return 0 if ok, 1 otherwise.
2065  */
2066 int
2067 nfsd_checkrootexp(struct nfsrv_descript *nd)
2068 {
2069
2070         if ((nd->nd_flag & (ND_GSS | ND_EXAUTHSYS)) == ND_EXAUTHSYS)
2071                 return (0);
2072         if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY)) ==
2073             (ND_GSSINTEGRITY | ND_EXGSSINTEGRITY))
2074                 return (0);
2075         if ((nd->nd_flag & (ND_GSSPRIVACY | ND_EXGSSPRIVACY)) ==
2076             (ND_GSSPRIVACY | ND_EXGSSPRIVACY))
2077                 return (0);
2078         if ((nd->nd_flag & (ND_GSS | ND_GSSINTEGRITY | ND_GSSPRIVACY |
2079              ND_EXGSS)) == (ND_GSS | ND_EXGSS))
2080                 return (0);
2081         return (1);
2082 }
2083
2084 /*
2085  * Parse the first part of an NFSv4 compound to find out what the minor
2086  * version# is.
2087  */
2088 void
2089 nfsd_getminorvers(struct nfsrv_descript *nd, u_char *tag, u_char **tagstrp,
2090     int *taglenp, u_int32_t *minversp)
2091 {
2092         uint32_t *tl;
2093         int error = 0, taglen = -1;
2094         u_char *tagstr = NULL;
2095
2096         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2097         taglen = fxdr_unsigned(int, *tl);
2098         if (taglen < 0 || taglen > NFSV4_OPAQUELIMIT) {
2099                 error = EBADRPC;
2100                 goto nfsmout;
2101         }
2102         if (taglen <= NFSV4_SMALLSTR)
2103                 tagstr = tag;
2104         else
2105                 tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
2106         error = nfsrv_mtostr(nd, tagstr, taglen);
2107         if (error != 0)
2108                 goto nfsmout;
2109         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2110         *minversp = fxdr_unsigned(u_int32_t, *tl);
2111         *tagstrp = tagstr;
2112         if (*minversp == NFSV41_MINORVERSION)
2113                 nd->nd_flag |= ND_NFSV41;
2114 nfsmout:
2115         if (error != 0) {
2116                 if (tagstr != NULL && taglen > NFSV4_SMALLSTR)
2117                         free(tagstr, M_TEMP);
2118                 taglen = -1;
2119         }
2120         *taglenp = taglen;
2121 }
2122