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