nfs_srvsubs.c revision 105481
1238730Sdelphij/*
2238730Sdelphij * Copyright (c) 1989, 1993
3238730Sdelphij *	The Regents of the University of California.  All rights reserved.
4238730Sdelphij *
5238730Sdelphij * This code is derived from software contributed to Berkeley by
6238730Sdelphij * Rick Macklem at The University of Guelph.
7238730Sdelphij *
8238730Sdelphij * Redistribution and use in source and binary forms, with or without
960786Sps * modification, are permitted provided that the following conditions
1060786Sps * are met:
1160786Sps * 1. Redistributions of source code must retain the above copyright
1260786Sps *    notice, this list of conditions and the following disclaimer.
1360786Sps * 2. Redistributions in binary form must reproduce the above copyright
1460786Sps *    notice, this list of conditions and the following disclaimer in the
1560786Sps *    documentation and/or other materials provided with the distribution.
1660786Sps * 3. All advertising materials mentioning features or use of this software
1760786Sps *    must display the following acknowledgement:
18161478Sdelphij *	This product includes software developed by the University of
1960786Sps *	California, Berkeley and its contributors.
20161478Sdelphij * 4. Neither the name of the University nor the names of its contributors
2189019Sps *    may be used to endorse or promote products derived from this software
2289019Sps *    without specific prior written permission.
2360786Sps *
24161478Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2560786Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2689019Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2789019Sps * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2889019Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29237613Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3060786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3160786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3260786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3360786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3460786Sps * SUCH DAMAGE.
35128345Stjr *
3660786Sps *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
3763128Sps * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 105481 2002-10-19 21:27:40Z rwatson $
3860786Sps */
3960786Sps
4060786Sps#include <sys/cdefs.h>
41161478Sdelphij__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 105481 2002-10-19 21:27:40Z rwatson $");
4260786Sps
43161478Sdelphij/*
44161478Sdelphij * These functions support the macros and help fiddle mbuf chains for
4560786Sps * the nfs op functions. They do things like create the rpc header and
4660786Sps * copy data between mbuf chains and uio lists.
47161478Sdelphij */
4860786Sps
4960786Sps#include "opt_inet6.h"
5060786Sps
5160786Sps#include <sys/param.h>
5260786Sps#include <sys/systm.h>
5363128Sps#include <sys/kernel.h>
5460786Sps#include <sys/bio.h>
5560786Sps#include <sys/buf.h>
5660786Sps#include <sys/proc.h>
5760786Sps#include <sys/mount.h>
5860786Sps#include <sys/vnode.h>
5960786Sps#include <sys/namei.h>
6060786Sps#include <sys/mbuf.h>
6163128Sps#include <sys/socket.h>
6263128Sps#include <sys/stat.h>
6360786Sps#include <sys/malloc.h>
64161478Sdelphij#include <sys/module.h>
65161478Sdelphij#include <sys/sysent.h>
66161478Sdelphij#include <sys/syscall.h>
67161478Sdelphij#include <sys/sysproto.h>
68161478Sdelphij
6960786Sps#include <vm/vm.h>
7060786Sps#include <vm/vm_object.h>
7160786Sps#include <vm/vm_extern.h>
7260786Sps#include <vm/uma.h>
7360786Sps
7460786Sps#include <nfs/rpcv2.h>
7560786Sps#include <nfs/nfsproto.h>
7660786Sps#include <nfsserver/nfs.h>
7760786Sps#include <nfs/xdr_subs.h>
78161478Sdelphij#include <nfsserver/nfsm_subs.h>
79161478Sdelphij
80161478Sdelphij#include <netinet/in.h>
81161478Sdelphij
82161478Sdelphij/*
8389019Sps * Data items converted to xdr at startup, since they are constant
8489019Sps * This is kinda hokey, but may save a little time doing byte swaps
8589019Sps */
8660786Spsu_int32_t nfsrv_nfs_xdrneg1;
8760786Spsu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
8860786Sps	nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
8989019Sps	nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
9089019Spsu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
91161478Sdelphij
9289019Sps/* And other global data */
9389019Spsstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
94161478Sdelphij				 NFNON, NFCHR, NFNON };
95161478Sdelphij#define vtonfsv2_type(a)	txdr_unsigned(nfsv2_type[((int32_t)(a))])
96161478Sdelphij#define vtonfsv3_mode(m)	txdr_unsigned((m) & ALLPERMS)
97161478Sdelphij
98161478Sdelphijint nfsrv_ticks;
99161478Sdelphij
100161478Sdelphijstruct nfssvc_sockhead nfssvc_sockhead;
101161478Sdelphijint nfssvc_sockhead_flag;
10289019Spsstruct nfsd_head nfsd_head;
10389019Spsint nfsd_head_flag;
104161478Sdelphij
10589019Spsstatic int nfs_prev_nfssvc_sy_narg;
10689019Spsstatic sy_call_t *nfs_prev_nfssvc_sy_call;
10789019Sps
10889019Sps/*
10989019Sps * Mapping of old NFS Version 2 RPC numbers to generic numbers.
11089019Sps */
11189019Spsint nfsrv_nfsv3_procid[NFS_NPROCS] = {
11289019Sps	NFSPROC_NULL,
113161478Sdelphij	NFSPROC_GETATTR,
114161478Sdelphij	NFSPROC_SETATTR,
115161478Sdelphij	NFSPROC_NOOP,
116161478Sdelphij	NFSPROC_LOOKUP,
117161478Sdelphij	NFSPROC_READLINK,
118161478Sdelphij	NFSPROC_READ,
119161478Sdelphij	NFSPROC_NOOP,
120161478Sdelphij	NFSPROC_WRITE,
121161478Sdelphij	NFSPROC_CREATE,
122161478Sdelphij	NFSPROC_REMOVE,
123161478Sdelphij	NFSPROC_RENAME,
124161478Sdelphij	NFSPROC_LINK,
12589019Sps	NFSPROC_SYMLINK,
12689019Sps	NFSPROC_MKDIR,
127128345Stjr	NFSPROC_RMDIR,
128128345Stjr	NFSPROC_READDIR,
129161478Sdelphij	NFSPROC_FSSTAT,
13089019Sps	NFSPROC_NOOP,
13189019Sps	NFSPROC_NOOP,
13289019Sps	NFSPROC_NOOP,
13389019Sps	NFSPROC_NOOP,
13489019Sps	NFSPROC_NOOP,
13589019Sps};
13689019Sps
137161478Sdelphij/*
138161478Sdelphij * and the reverse mapping from generic to Version 2 procedure numbers
139161478Sdelphij */
140161478Sdelphijint nfsrvv2_procid[NFS_NPROCS] = {
141161478Sdelphij	NFSV2PROC_NULL,
142161478Sdelphij	NFSV2PROC_GETATTR,
143161478Sdelphij	NFSV2PROC_SETATTR,
144161478Sdelphij	NFSV2PROC_LOOKUP,
145161478Sdelphij	NFSV2PROC_NOOP,
146161478Sdelphij	NFSV2PROC_READLINK,
14760786Sps	NFSV2PROC_READ,
14860786Sps	NFSV2PROC_WRITE,
14960786Sps	NFSV2PROC_CREATE,
15060786Sps	NFSV2PROC_MKDIR,
15160786Sps	NFSV2PROC_SYMLINK,
15260786Sps	NFSV2PROC_CREATE,
15360786Sps	NFSV2PROC_REMOVE,
154161478Sdelphij	NFSV2PROC_RMDIR,
15560786Sps	NFSV2PROC_RENAME,
156161478Sdelphij	NFSV2PROC_LINK,
157161478Sdelphij	NFSV2PROC_READDIR,
15860786Sps	NFSV2PROC_NOOP,
15960786Sps	NFSV2PROC_STATFS,
16063128Sps	NFSV2PROC_NOOP,
161128345Stjr	NFSV2PROC_NOOP,
162128345Stjr	NFSV2PROC_NOOP,
16360786Sps	NFSV2PROC_NOOP,
16460786Sps};
16560786Sps
16660786Sps/*
16760786Sps * Maps errno values to nfs error numbers.
16860786Sps * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
16960786Sps * specifically defined in RFC 1094.
17060786Sps */
17160786Spsstatic u_char nfsrv_v2errmap[ELAST] = {
172128345Stjr  NFSERR_PERM,	NFSERR_NOENT,	0,		0,		0,
17360786Sps  NFSERR_NXIO,	0,		0,		0,		0,
17460786Sps  0,		0,		NFSERR_ACCES,	0,		0,
17563128Sps  0,		NFSERR_EXIST,	0,		NFSERR_NODEV,	NFSERR_NOTDIR,
17663128Sps  NFSERR_ISDIR,	0,		0,		0,		0,
17763128Sps  0,		NFSERR_FBIG,	NFSERR_NOSPC,	0,		NFSERR_ROFS,
17863128Sps  0,		0,		0,		0,		0,
17963128Sps  0,		0,		0,		0,		0,
18063128Sps  0,		0,		0,		0,		0,
18163128Sps  0,		0,		0,		0,		0,
18263128Sps  0,		0,		0,		0,		0,
18363128Sps  0,		0,		0,		0,		0,
18463128Sps  0,		0,		NFSERR_NAMETOL,	0,		0,
185128345Stjr  NFSERR_NOTEMPTY, 0,		0,		NFSERR_DQUOT,	NFSERR_STALE,
18663128Sps  0
18763128Sps};
18860786Sps
18963128Sps/*
19060786Sps * Maps errno values to nfs error numbers.
19163128Sps * Although it is not obvious whether or not NFS clients really care if
19263128Sps * a returned error value is in the specified list for the procedure, the
19363128Sps * safest thing to do is filter them appropriately. For Version 2, the
19463128Sps * X/Open XNFS document is the only specification that defines error values
19563128Sps * for each RPC (The RFC simply lists all possible error values for all RPCs),
196161478Sdelphij * so I have decided to not do this for Version 2.
19763128Sps * The first entry is the default error return and the rest are the valid
198161478Sdelphij * errors for that RPC in increasing numeric order.
19963128Sps */
20063128Spsstatic short nfsv3err_null[] = {
20163128Sps	0,
20260786Sps	0,
20363128Sps};
20463128Sps
20560786Spsstatic short nfsv3err_getattr[] = {
20663128Sps	NFSERR_IO,
20763128Sps	NFSERR_IO,
208128345Stjr	NFSERR_STALE,
209128345Stjr	NFSERR_BADHANDLE,
210128345Stjr	NFSERR_SERVERFAULT,
211128345Stjr	0,
212128345Stjr};
213128345Stjr
214128345Stjrstatic short nfsv3err_setattr[] = {
215128345Stjr	NFSERR_IO,
216128345Stjr	NFSERR_PERM,
217128345Stjr	NFSERR_IO,
218128345Stjr	NFSERR_ACCES,
219128345Stjr	NFSERR_INVAL,
220128345Stjr	NFSERR_NOSPC,
221128345Stjr	NFSERR_ROFS,
22263128Sps	NFSERR_DQUOT,
223128345Stjr	NFSERR_STALE,
22460786Sps	NFSERR_BADHANDLE,
22563128Sps	NFSERR_NOT_SYNC,
22660786Sps	NFSERR_SERVERFAULT,
22763128Sps	0,
22860786Sps};
22960786Sps
23060786Spsstatic short nfsv3err_lookup[] = {
23160786Sps	NFSERR_IO,
23263128Sps	NFSERR_NOENT,
23360786Sps	NFSERR_IO,
23460786Sps	NFSERR_ACCES,
23560786Sps	NFSERR_NOTDIR,
236161478Sdelphij	NFSERR_NAMETOL,
237161478Sdelphij	NFSERR_STALE,
23860786Sps	NFSERR_BADHANDLE,
239161478Sdelphij	NFSERR_SERVERFAULT,
240161478Sdelphij	0,
241161478Sdelphij};
242161478Sdelphij
243161478Sdelphijstatic short nfsv3err_access[] = {
244161478Sdelphij	NFSERR_IO,
245161478Sdelphij	NFSERR_IO,
246161478Sdelphij	NFSERR_STALE,
247161478Sdelphij	NFSERR_BADHANDLE,
24889019Sps	NFSERR_SERVERFAULT,
249161478Sdelphij	0,
250161478Sdelphij};
251161478Sdelphij
25289019Spsstatic short nfsv3err_readlink[] = {
253161478Sdelphij	NFSERR_IO,
254161478Sdelphij	NFSERR_IO,
255161478Sdelphij	NFSERR_ACCES,
256161478Sdelphij	NFSERR_INVAL,
257161478Sdelphij	NFSERR_STALE,
258161478Sdelphij	NFSERR_BADHANDLE,
25989019Sps	NFSERR_NOTSUPP,
260161478Sdelphij	NFSERR_SERVERFAULT,
261161478Sdelphij	0,
26289019Sps};
263161478Sdelphij
26489019Spsstatic short nfsv3err_read[] = {
265161478Sdelphij	NFSERR_IO,
266172471Sdelphij	NFSERR_IO,
26789019Sps	NFSERR_NXIO,
268161478Sdelphij	NFSERR_ACCES,
269161478Sdelphij	NFSERR_INVAL,
270161478Sdelphij	NFSERR_STALE,
271161478Sdelphij	NFSERR_BADHANDLE,
272161478Sdelphij	NFSERR_SERVERFAULT,
273161478Sdelphij	0,
274161478Sdelphij};
275161478Sdelphij
276161478Sdelphijstatic short nfsv3err_write[] = {
277161478Sdelphij	NFSERR_IO,
278161478Sdelphij	NFSERR_IO,
279161478Sdelphij	NFSERR_ACCES,
280161478Sdelphij	NFSERR_INVAL,
281161478Sdelphij	NFSERR_FBIG,
282161478Sdelphij	NFSERR_NOSPC,
283161478Sdelphij	NFSERR_ROFS,
284161478Sdelphij	NFSERR_DQUOT,
285161478Sdelphij	NFSERR_STALE,
286161478Sdelphij	NFSERR_BADHANDLE,
287161478Sdelphij	NFSERR_SERVERFAULT,
288161478Sdelphij	0,
289161478Sdelphij};
290161478Sdelphij
291161478Sdelphijstatic short nfsv3err_create[] = {
292161478Sdelphij	NFSERR_IO,
293161478Sdelphij	NFSERR_IO,
294161478Sdelphij	NFSERR_ACCES,
29589019Sps	NFSERR_EXIST,
29689019Sps	NFSERR_NOTDIR,
297161478Sdelphij	NFSERR_NOSPC,
298161478Sdelphij	NFSERR_ROFS,
299161478Sdelphij	NFSERR_NAMETOL,
300161478Sdelphij	NFSERR_DQUOT,
301161478Sdelphij	NFSERR_STALE,
302161478Sdelphij	NFSERR_BADHANDLE,
303161478Sdelphij	NFSERR_NOTSUPP,
304161478Sdelphij	NFSERR_SERVERFAULT,
305161478Sdelphij	0,
306161478Sdelphij};
307161478Sdelphij
308161478Sdelphijstatic short nfsv3err_mkdir[] = {
309161478Sdelphij	NFSERR_IO,
310161478Sdelphij	NFSERR_IO,
311161478Sdelphij	NFSERR_ACCES,
312161478Sdelphij	NFSERR_EXIST,
313161478Sdelphij	NFSERR_NOTDIR,
314161478Sdelphij	NFSERR_NOSPC,
315161478Sdelphij	NFSERR_ROFS,
316161478Sdelphij	NFSERR_NAMETOL,
317161478Sdelphij	NFSERR_DQUOT,
318161478Sdelphij	NFSERR_STALE,
319161478Sdelphij	NFSERR_BADHANDLE,
320161478Sdelphij	NFSERR_NOTSUPP,
321161478Sdelphij	NFSERR_SERVERFAULT,
322161478Sdelphij	0,
323161478Sdelphij};
324161478Sdelphij
325161478Sdelphijstatic short nfsv3err_symlink[] = {
326161478Sdelphij	NFSERR_IO,
327161478Sdelphij	NFSERR_IO,
328161478Sdelphij	NFSERR_ACCES,
329161478Sdelphij	NFSERR_EXIST,
33089019Sps	NFSERR_NOTDIR,
331161478Sdelphij	NFSERR_NOSPC,
332161478Sdelphij	NFSERR_ROFS,
333161478Sdelphij	NFSERR_NAMETOL,
33489019Sps	NFSERR_DQUOT,
33589019Sps	NFSERR_STALE,
33689019Sps	NFSERR_BADHANDLE,
337161478Sdelphij	NFSERR_NOTSUPP,
338161478Sdelphij	NFSERR_SERVERFAULT,
339161478Sdelphij	0,
340161478Sdelphij};
341161478Sdelphij
342161478Sdelphijstatic short nfsv3err_mknod[] = {
34360786Sps	NFSERR_IO,
344161478Sdelphij	NFSERR_IO,
34560786Sps	NFSERR_ACCES,
346161478Sdelphij	NFSERR_EXIST,
347161478Sdelphij	NFSERR_NOTDIR,
34860786Sps	NFSERR_NOSPC,
349161478Sdelphij	NFSERR_ROFS,
350161478Sdelphij	NFSERR_NAMETOL,
351161478Sdelphij	NFSERR_DQUOT,
35260786Sps	NFSERR_STALE,
35360786Sps	NFSERR_BADHANDLE,
35460786Sps	NFSERR_NOTSUPP,
355161478Sdelphij	NFSERR_SERVERFAULT,
35660786Sps	NFSERR_BADTYPE,
357161478Sdelphij	0,
358161478Sdelphij};
35960786Sps
360161478Sdelphijstatic short nfsv3err_remove[] = {
36160786Sps	NFSERR_IO,
36260786Sps	NFSERR_NOENT,
36360786Sps	NFSERR_IO,
36460786Sps	NFSERR_ACCES,
36560786Sps	NFSERR_NOTDIR,
36660786Sps	NFSERR_ROFS,
36760786Sps	NFSERR_NAMETOL,
36860786Sps	NFSERR_STALE,
36960786Sps	NFSERR_BADHANDLE,
37060786Sps	NFSERR_SERVERFAULT,
371161478Sdelphij	0,
372161478Sdelphij};
373161478Sdelphij
374161478Sdelphijstatic short nfsv3err_rmdir[] = {
375161478Sdelphij	NFSERR_IO,
376161478Sdelphij	NFSERR_NOENT,
377161478Sdelphij	NFSERR_IO,
378161478Sdelphij	NFSERR_ACCES,
379161478Sdelphij	NFSERR_EXIST,
380161478Sdelphij	NFSERR_NOTDIR,
381161478Sdelphij	NFSERR_INVAL,
382161478Sdelphij	NFSERR_ROFS,
383161478Sdelphij	NFSERR_NAMETOL,
384161478Sdelphij	NFSERR_NOTEMPTY,
38560786Sps	NFSERR_STALE,
38660786Sps	NFSERR_BADHANDLE,
38760786Sps	NFSERR_NOTSUPP,
38860786Sps	NFSERR_SERVERFAULT,
38960786Sps	0,
39060786Sps};
39160786Sps
39260786Spsstatic short nfsv3err_rename[] = {
39360786Sps	NFSERR_IO,
39460786Sps	NFSERR_NOENT,
395161478Sdelphij	NFSERR_IO,
396161478Sdelphij	NFSERR_ACCES,
397161478Sdelphij	NFSERR_EXIST,
398161478Sdelphij	NFSERR_XDEV,
399161478Sdelphij	NFSERR_NOTDIR,
400161478Sdelphij	NFSERR_ISDIR,
401161478Sdelphij	NFSERR_INVAL,
402161478Sdelphij	NFSERR_NOSPC,
403161478Sdelphij	NFSERR_ROFS,
404161478Sdelphij	NFSERR_MLINK,
405161478Sdelphij	NFSERR_NAMETOL,
406161478Sdelphij	NFSERR_NOTEMPTY,
407161478Sdelphij	NFSERR_DQUOT,
408161478Sdelphij	NFSERR_STALE,
40960786Sps	NFSERR_BADHANDLE,
41060786Sps	NFSERR_NOTSUPP,
41160786Sps	NFSERR_SERVERFAULT,
41260786Sps	0,
41360786Sps};
41460786Sps
41560786Spsstatic short nfsv3err_link[] = {
41660786Sps	NFSERR_IO,
41760786Sps	NFSERR_IO,
418161478Sdelphij	NFSERR_ACCES,
419161478Sdelphij	NFSERR_EXIST,
42060786Sps	NFSERR_XDEV,
421161478Sdelphij	NFSERR_NOTDIR,
42260786Sps	NFSERR_INVAL,
423161478Sdelphij	NFSERR_NOSPC,
42460786Sps	NFSERR_ROFS,
425161478Sdelphij	NFSERR_MLINK,
42660786Sps	NFSERR_NAMETOL,
427161478Sdelphij	NFSERR_DQUOT,
428161478Sdelphij	NFSERR_STALE,
42960786Sps	NFSERR_BADHANDLE,
430161478Sdelphij	NFSERR_NOTSUPP,
43160786Sps	NFSERR_SERVERFAULT,
432161478Sdelphij	0,
433161478Sdelphij};
434161478Sdelphij
435161478Sdelphijstatic short nfsv3err_readdir[] = {
436161478Sdelphij	NFSERR_IO,
437161478Sdelphij	NFSERR_IO,
438161478Sdelphij	NFSERR_ACCES,
439161478Sdelphij	NFSERR_NOTDIR,
440161478Sdelphij	NFSERR_STALE,
441161478Sdelphij	NFSERR_BADHANDLE,
442161478Sdelphij	NFSERR_BAD_COOKIE,
443161478Sdelphij	NFSERR_TOOSMALL,
444161478Sdelphij	NFSERR_SERVERFAULT,
445161478Sdelphij	0,
446161478Sdelphij};
447161478Sdelphij
448161478Sdelphijstatic short nfsv3err_readdirplus[] = {
449161478Sdelphij	NFSERR_IO,
450161478Sdelphij	NFSERR_IO,
451161478Sdelphij	NFSERR_ACCES,
452161478Sdelphij	NFSERR_NOTDIR,
453161478Sdelphij	NFSERR_STALE,
454161478Sdelphij	NFSERR_BADHANDLE,
455161478Sdelphij	NFSERR_BAD_COOKIE,
456161478Sdelphij	NFSERR_NOTSUPP,
457161478Sdelphij	NFSERR_TOOSMALL,
458161478Sdelphij	NFSERR_SERVERFAULT,
459161478Sdelphij	0,
460161478Sdelphij};
46160786Sps
46260786Spsstatic short nfsv3err_fsstat[] = {
463161478Sdelphij	NFSERR_IO,
46460786Sps	NFSERR_IO,
46560786Sps	NFSERR_STALE,
46660786Sps	NFSERR_BADHANDLE,
467161478Sdelphij	NFSERR_SERVERFAULT,
468161478Sdelphij	0,
469161478Sdelphij};
47060786Sps
471161478Sdelphijstatic short nfsv3err_fsinfo[] = {
472161478Sdelphij	NFSERR_STALE,
47360786Sps	NFSERR_STALE,
47460786Sps	NFSERR_BADHANDLE,
47560786Sps	NFSERR_SERVERFAULT,
47660786Sps	0,
47760786Sps};
478161478Sdelphij
479161478Sdelphijstatic short nfsv3err_pathconf[] = {
48060786Sps	NFSERR_STALE,
481161478Sdelphij	NFSERR_STALE,
48260786Sps	NFSERR_BADHANDLE,
48360786Sps	NFSERR_SERVERFAULT,
484161478Sdelphij	0,
485161478Sdelphij};
486161478Sdelphij
487161478Sdelphijstatic short nfsv3err_commit[] = {
488161478Sdelphij	NFSERR_IO,
489161478Sdelphij	NFSERR_IO,
490161478Sdelphij	NFSERR_STALE,
491161478Sdelphij	NFSERR_BADHANDLE,
492161478Sdelphij	NFSERR_SERVERFAULT,
493161478Sdelphij	0,
494161478Sdelphij};
495161478Sdelphij
496161478Sdelphijstatic short *nfsrv_v3errmap[] = {
497161478Sdelphij	nfsv3err_null,
498161478Sdelphij	nfsv3err_getattr,
499161478Sdelphij	nfsv3err_setattr,
500161478Sdelphij	nfsv3err_lookup,
501161478Sdelphij	nfsv3err_access,
502161478Sdelphij	nfsv3err_readlink,
503161478Sdelphij	nfsv3err_read,
50460786Sps	nfsv3err_write,
50560786Sps	nfsv3err_create,
50660786Sps	nfsv3err_mkdir,
50760786Sps	nfsv3err_symlink,
50860786Sps	nfsv3err_mknod,
50960786Sps	nfsv3err_remove,
51060786Sps	nfsv3err_rmdir,
51160786Sps	nfsv3err_rename,
512161478Sdelphij	nfsv3err_link,
51360786Sps	nfsv3err_readdir,
51460786Sps	nfsv3err_readdirplus,
51560786Sps	nfsv3err_fsstat,
51660786Sps	nfsv3err_fsinfo,
51760786Sps	nfsv3err_pathconf,
518161478Sdelphij	nfsv3err_commit,
51960786Sps};
520161478Sdelphij
521172471Sdelphij/*
52260786Sps * Called once to initialize data structures...
523161478Sdelphij */
52460786Spsstatic int
52560786Spsnfsrv_modevent(module_t mod, int type, void *data)
52660786Sps{
52760786Sps
52860786Sps	switch (type) {
52960786Sps	case MOD_LOAD:
53089019Sps		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
53189019Sps		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
53289019Sps		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
533161478Sdelphij		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
534161478Sdelphij		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
53589019Sps		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
536161478Sdelphij		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
537161478Sdelphij		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
538161478Sdelphij		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
53989019Sps		nfsrv_nfs_true = txdr_unsigned(TRUE);
54089019Sps		nfsrv_nfs_false = txdr_unsigned(FALSE);
54189019Sps		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
542161478Sdelphij		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
543161478Sdelphij		if (nfsrv_ticks < 1)
544161478Sdelphij			nfsrv_ticks = 1;
545161478Sdelphij
546161478Sdelphij		nfsrv_init(0);		/* Init server data structures */
547161478Sdelphij		nfsrv_initcache();	/* Init the server request cache */
548161478Sdelphij
549161478Sdelphij		nfsrv_timer(0);
550161478Sdelphij
551161478Sdelphij		nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
552161478Sdelphij		sysent[SYS_nfssvc].sy_narg = 2;
553161478Sdelphij		nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
554161478Sdelphij		sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
555161478Sdelphij		break;
55660786Sps
55760786Sps		case MOD_UNLOAD:
558161478Sdelphij
559161478Sdelphij		untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle);
560161478Sdelphij		sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
561161478Sdelphij		sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
56289019Sps		break;
56360786Sps	}
564161478Sdelphij	return 0;
565161478Sdelphij}
56660786Spsstatic moduledata_t nfsserver_mod = {
567161478Sdelphij	"nfsserver",
56860786Sps	nfsrv_modevent,
56960786Sps	NULL,
570161478Sdelphij};
571161478SdelphijDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
572161478Sdelphij
57360786Sps/* So that loader and kldload(2) can find us, wherever we are.. */
574161478SdelphijMODULE_VERSION(nfsserver, 1);
575161478Sdelphij
576161478Sdelphij/*
577161478Sdelphij * Set up nameidata for a lookup() call and do it.
57860786Sps *
57989019Sps * If pubflag is set, this call is done for a lookup operation on the
580161478Sdelphij * public filehandle. In that case we allow crossing mountpoints and
581161478Sdelphij * absolute pathnames. However, the caller is expected to check that
582161478Sdelphij * the lookup result is within the public fs, and deny access if
583161478Sdelphij * it is not.
584161478Sdelphij *
585161478Sdelphij * nfs_namei() clears out garbage fields that namei() might leave garbage.
586161478Sdelphij * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
587161478Sdelphij * error occurs but the parent was not requested.
588237613Sdelphij *
589237613Sdelphij * dirp may be set whether an error is returned or not, and must be
590237613Sdelphij * released by the caller.
591237613Sdelphij */
592161478Sdelphijint
593237613Sdelphijnfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
594161478Sdelphij    struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
59589019Sps    caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag)
59660786Sps{
597161478Sdelphij	int i, rem;
59860786Sps	struct mbuf *md;
599161478Sdelphij	char *fromcp, *tocp, *cp;
600161478Sdelphij	struct iovec aiov;
601161478Sdelphij	struct uio auio;
602191930Sdelphij	struct vnode *dp;
603191930Sdelphij	int error, rdonly, linklen;
604191930Sdelphij	struct componentname *cnp = &ndp->ni_cnd;
605191930Sdelphij
606191930Sdelphij	*retdirp = NULL;
607191930Sdelphij	cnp->cn_flags |= NOMACCHECK;
608161478Sdelphij	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
609161478Sdelphij
610161478Sdelphij	/*
61160786Sps	 * Copy the name from the mbuf list to ndp->ni_pnbuf
612161478Sdelphij	 * and set the various ndp fields appropriately.
613172471Sdelphij	 */
614161478Sdelphij	fromcp = *dposp;
615161478Sdelphij	tocp = cnp->cn_pnbuf;
616161478Sdelphij	md = *mdp;
617161478Sdelphij	rem = mtod(md, caddr_t) + md->m_len - fromcp;
61860786Sps	for (i = 0; i < len; i++) {
619161478Sdelphij		while (rem == 0) {
620161478Sdelphij			md = md->m_next;
621161478Sdelphij			if (md == NULL) {
622161478Sdelphij				error = EBADRPC;
623161478Sdelphij				goto out;
624161478Sdelphij			}
62560786Sps			fromcp = mtod(md, caddr_t);
62660786Sps			rem = md->m_len;
62760786Sps		}
62860786Sps		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
62960786Sps			error = EACCES;
63060786Sps			goto out;
631161478Sdelphij		}
63289019Sps		*tocp++ = *fromcp++;
633161478Sdelphij		rem--;
634161478Sdelphij	}
635161478Sdelphij	*tocp = '\0';
636161478Sdelphij	*mdp = md;
637161478Sdelphij	*dposp = fromcp;
638161478Sdelphij	len = nfsm_rndup(len)-len;
639161478Sdelphij	if (len > 0) {
640161478Sdelphij		if (rem >= len)
641161478Sdelphij			*dposp += len;
64260786Sps		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
64360786Sps			goto out;
64489019Sps	}
64560786Sps
64689019Sps	/*
64789019Sps	 * Extract and set starting directory.
64889019Sps	 */
64960786Sps	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
650161478Sdelphij	    nam, &rdonly, pubflag);
65160786Sps	if (error)
652161478Sdelphij		goto out;
653161478Sdelphij	if (dp->v_type != VDIR) {
654161478Sdelphij		vrele(dp);
65560786Sps		error = ENOTDIR;
65660786Sps		goto out;
65760786Sps	}
65860786Sps
65960786Sps	if (rdonly)
66060786Sps		cnp->cn_flags |= RDONLY;
66189019Sps
66289019Sps	/*
66389019Sps	 * Set return directory.  Reference to dp is implicitly transfered
66489019Sps	 * to the returned pointer
66589019Sps	 */
66689019Sps	*retdirp = dp;
66789019Sps
66889019Sps	if (pubflag) {
66989019Sps		/*
67089019Sps		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
67189019Sps		 * and the 'native path' indicator.
67289019Sps		 */
67389019Sps		cp = uma_zalloc(namei_zone, M_WAITOK);
67489019Sps		fromcp = cnp->cn_pnbuf;
67589019Sps		tocp = cp;
67689019Sps		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
67789019Sps			switch ((unsigned char)*fromcp) {
67889019Sps			case WEBNFS_NATIVE_CHAR:
67989019Sps				/*
68089019Sps				 * 'Native' path for us is the same
68189019Sps				 * as a path according to the NFS spec,
68289019Sps				 * just skip the escape char.
68389019Sps				 */
68489019Sps				fromcp++;
68589019Sps				break;
686161478Sdelphij			/*
687161478Sdelphij			 * More may be added in the future, range 0x80-0xff
688161478Sdelphij			 */
68989019Sps			default:
690161478Sdelphij				error = EIO;
69189019Sps				uma_zfree(namei_zone, cp);
69289019Sps				goto out;
69389019Sps			}
69489019Sps		}
695161478Sdelphij		/*
696161478Sdelphij		 * Translate the '%' escapes, URL-style.
697161478Sdelphij		 */
698161478Sdelphij		while (*fromcp != '\0') {
699161478Sdelphij			if (*fromcp == WEBNFS_ESC_CHAR) {
700161478Sdelphij				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
701161478Sdelphij					fromcp++;
702161478Sdelphij					*tocp++ = HEXSTRTOI(fromcp);
703161478Sdelphij					fromcp += 2;
704161478Sdelphij					continue;
705161478Sdelphij				} else {
706161478Sdelphij					error = ENOENT;
707161478Sdelphij					uma_zfree(namei_zone, cp);
708161478Sdelphij					goto out;
709161478Sdelphij				}
710161478Sdelphij			} else
711161478Sdelphij				*tocp++ = *fromcp++;
712161478Sdelphij		}
713161478Sdelphij		*tocp = '\0';
714161478Sdelphij		uma_zfree(namei_zone, cnp->cn_pnbuf);
715161478Sdelphij		cnp->cn_pnbuf = cp;
716161478Sdelphij	}
717161478Sdelphij
718161478Sdelphij	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
719161478Sdelphij	ndp->ni_segflg = UIO_SYSSPACE;
720161478Sdelphij
721161478Sdelphij	if (pubflag) {
722161478Sdelphij		ndp->ni_rootdir = rootvnode;
723161478Sdelphij		ndp->ni_loopcnt = 0;
724161478Sdelphij		if (cnp->cn_pnbuf[0] == '/')
725161478Sdelphij			dp = rootvnode;
726161478Sdelphij	} else {
727161478Sdelphij		cnp->cn_flags |= NOCROSSMOUNT;
728161478Sdelphij	}
729161478Sdelphij
730161478Sdelphij	/*
731161478Sdelphij	 * Initialize for scan, set ni_startdir and bump ref on dp again
732161478Sdelphij	 * becuase lookup() will dereference ni_startdir.
733161478Sdelphij	 */
734161478Sdelphij
735161478Sdelphij	cnp->cn_thread = td;
736161478Sdelphij	VREF(dp);
73789019Sps	ndp->ni_startdir = dp;
73860786Sps
73960786Sps	for (;;) {
74060786Sps		cnp->cn_nameptr = cnp->cn_pnbuf;
74160786Sps		/*
74260786Sps		 * Call lookup() to do the real work.  If an error occurs,
74360786Sps		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
744161478Sdelphij		 * we do not have to dereference anything before returning.
74560786Sps		 * In either case ni_startdir will be dereferenced and NULLed
74660786Sps		 * out.
74760786Sps		 */
74860786Sps		error = lookup(ndp);
74960786Sps		if (error)
75060786Sps			break;
751161478Sdelphij
75260786Sps		/*
75360786Sps		 * Check for encountering a symbolic link.  Trivial
75460786Sps		 * termination occurs if no symlink encountered.
75560786Sps		 * Note: zfree is safe because error is 0, so we will
75660786Sps		 * not zfree it again when we break.
75760786Sps		 */
75860786Sps		if ((cnp->cn_flags & ISSYMLINK) == 0) {
75960786Sps			nfsrv_object_create(ndp->ni_vp);
76060786Sps			if (cnp->cn_flags & (SAVENAME | SAVESTART))
76160786Sps				cnp->cn_flags |= HASBUF;
762161478Sdelphij			else
763161478Sdelphij				uma_zfree(namei_zone, cnp->cn_pnbuf);
764161478Sdelphij			break;
765161478Sdelphij		}
766161478Sdelphij
767161478Sdelphij		/*
768161478Sdelphij		 * Validate symlink
769161478Sdelphij		 */
770161478Sdelphij		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
771161478Sdelphij			VOP_UNLOCK(ndp->ni_dvp, 0, td);
77260786Sps		if (!pubflag) {
77360786Sps			error = EINVAL;
77460786Sps			goto badlink2;
77560786Sps		}
77660786Sps
77760786Sps		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
77860786Sps			error = ELOOP;
77960786Sps			goto badlink2;
78060786Sps		}
78160786Sps		if (ndp->ni_pathlen > 1)
782161478Sdelphij			cp = uma_zalloc(namei_zone, M_WAITOK);
783161478Sdelphij		else
784161478Sdelphij			cp = cnp->cn_pnbuf;
785161478Sdelphij		aiov.iov_base = cp;
786161478Sdelphij		aiov.iov_len = MAXPATHLEN;
787161478Sdelphij		auio.uio_iov = &aiov;
788161478Sdelphij		auio.uio_iovcnt = 1;
789161478Sdelphij		auio.uio_offset = 0;
790161478Sdelphij		auio.uio_rw = UIO_READ;
791161478Sdelphij		auio.uio_segflg = UIO_SYSSPACE;
792161478Sdelphij		auio.uio_td = NULL;
793161478Sdelphij		auio.uio_resid = MAXPATHLEN;
794161478Sdelphij		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
795161478Sdelphij		if (error) {
796161478Sdelphij		badlink1:
797161478Sdelphij			if (ndp->ni_pathlen > 1)
798161478Sdelphij				uma_zfree(namei_zone, cp);
799161478Sdelphij		badlink2:
800161478Sdelphij			vrele(ndp->ni_dvp);
801161478Sdelphij			vput(ndp->ni_vp);
802161478Sdelphij			break;
803161478Sdelphij		}
804161478Sdelphij		linklen = MAXPATHLEN - auio.uio_resid;
805161478Sdelphij		if (linklen == 0) {
806161478Sdelphij			error = ENOENT;
807161478Sdelphij			goto badlink1;
808161478Sdelphij		}
809161478Sdelphij		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
810161478Sdelphij			error = ENAMETOOLONG;
811161478Sdelphij			goto badlink1;
812161478Sdelphij		}
813161478Sdelphij
814161478Sdelphij		/*
815161478Sdelphij		 * Adjust or replace path
816161478Sdelphij		 */
817161478Sdelphij		if (ndp->ni_pathlen > 1) {
818161478Sdelphij			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
819161478Sdelphij			uma_zfree(namei_zone, cnp->cn_pnbuf);
820161478Sdelphij			cnp->cn_pnbuf = cp;
821161478Sdelphij		} else
822161478Sdelphij			cnp->cn_pnbuf[linklen] = '\0';
823161478Sdelphij		ndp->ni_pathlen += linklen;
824161478Sdelphij
825161478Sdelphij		/*
82660786Sps		 * Cleanup refs for next loop and check if root directory
82760786Sps		 * should replace current directory.  Normally ni_dvp
82860786Sps		 * becomes the new base directory and is cleaned up when
82960786Sps		 * we loop.  Explicitly null pointers after invalidation
83060786Sps		 * to clarify operation.
83160786Sps		 */
83260786Sps		vput(ndp->ni_vp);
83389019Sps		ndp->ni_vp = NULL;
83489019Sps
83560786Sps		if (cnp->cn_pnbuf[0] == '/') {
83689019Sps			vrele(ndp->ni_dvp);
837161478Sdelphij			ndp->ni_dvp = ndp->ni_rootdir;
838161478Sdelphij			VREF(ndp->ni_dvp);
839161478Sdelphij		}
840161478Sdelphij		ndp->ni_startdir = ndp->ni_dvp;
841161478Sdelphij		ndp->ni_dvp = NULL;
84260786Sps	}
84360786Sps
84460786Sps	/*
84560786Sps	 * nfs_namei() guarentees that fields will not contain garbage
846161478Sdelphij	 * whether an error occurs or not.  This allows the caller to track
847161478Sdelphij	 * cleanup state trivially.
848161478Sdelphij	 */
84960786Spsout:
85060786Sps	if (error) {
85160786Sps		uma_zfree(namei_zone, cnp->cn_pnbuf);
852161478Sdelphij		ndp->ni_vp = NULL;
85360786Sps		ndp->ni_dvp = NULL;
854161478Sdelphij		ndp->ni_startdir = NULL;
85560786Sps		cnp->cn_flags &= ~HASBUF;
856161478Sdelphij	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
85760786Sps		ndp->ni_dvp = NULL;
858161478Sdelphij	}
85960786Sps	return (error);
860161478Sdelphij}
861161478Sdelphij
862161478Sdelphij/*
863161478Sdelphij * A fiddled version of m_adj() that ensures null fill to a long
864161478Sdelphij * boundary and only trims off the back end
865161478Sdelphij */
866161478Sdelphijvoid
867161478Sdelphijnfsm_adj(struct mbuf *mp, int len, int nul)
868161478Sdelphij{
869161478Sdelphij	struct mbuf *m;
870161478Sdelphij	int count, i;
871161478Sdelphij	char *cp;
872161478Sdelphij
873161478Sdelphij	/*
874161478Sdelphij	 * Trim from tail.  Scan the mbuf chain,
875161478Sdelphij	 * calculating its length and finding the last mbuf.
876161478Sdelphij	 * If the adjustment only affects this mbuf, then just
877161478Sdelphij	 * adjust and return.  Otherwise, rescan and truncate
878161478Sdelphij	 * after the remaining size.
87960786Sps	 */
88060786Sps	count = 0;
88160786Sps	m = mp;
88260786Sps	for (;;) {
88360786Sps		count += m->m_len;
88460786Sps		if (m->m_next == NULL)
88560786Sps			break;
88660786Sps		m = m->m_next;
887161478Sdelphij	}
888161478Sdelphij	if (m->m_len > len) {
889161478Sdelphij		m->m_len -= len;
890161478Sdelphij		if (nul > 0) {
891161478Sdelphij			cp = mtod(m, caddr_t)+m->m_len-nul;
89289019Sps			for (i = 0; i < nul; i++)
893128345Stjr				*cp++ = '\0';
894128345Stjr		}
895128345Stjr		return;
896128345Stjr	}
897128345Stjr	count -= len;
898128345Stjr	if (count < 0)
899128345Stjr		count = 0;
900161478Sdelphij	/*
90189019Sps	 * Correct length for chain is "count".
902161478Sdelphij	 * Find the mbuf with last data, adjust its length,
903161478Sdelphij	 * and toss data from remaining mbufs on chain.
904161478Sdelphij	 */
905161478Sdelphij	for (m = mp; m; m = m->m_next) {
906161478Sdelphij		if (m->m_len >= count) {
907161478Sdelphij			m->m_len = count;
908161478Sdelphij			if (nul > 0) {
909161478Sdelphij				cp = mtod(m, caddr_t)+m->m_len-nul;
910161478Sdelphij				for (i = 0; i < nul; i++)
91189019Sps					*cp++ = '\0';
912161478Sdelphij			}
913161478Sdelphij			break;
914161478Sdelphij		}
915161478Sdelphij		count -= m->m_len;
916161478Sdelphij	}
917161478Sdelphij	for (m = m->m_next;m;m = m->m_next)
918161478Sdelphij		m->m_len = 0;
919161478Sdelphij}
920161478Sdelphij
921161478Sdelphij/*
922161478Sdelphij * Make these functions instead of macros, so that the kernel text size
923161478Sdelphij * doesn't get too big...
924161478Sdelphij */
925161478Sdelphijvoid
92660786Spsnfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
927161478Sdelphij    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
928161478Sdelphij    struct mbuf **mbp, char **bposp)
929161478Sdelphij{
930161478Sdelphij	struct mbuf *mb = *mbp;
93160786Sps	char *bpos = *bposp;
93260786Sps	u_int32_t *tl;
93360786Sps
93460786Sps	if (before_ret) {
93560786Sps		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
93660786Sps		*tl = nfsrv_nfs_false;
93760786Sps	} else {
93860786Sps		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
93960786Sps		*tl++ = nfsrv_nfs_true;
94060786Sps		txdr_hyper(before_vap->va_size, tl);
941161478Sdelphij		tl += 2;
94260786Sps		txdr_nfsv3time(&(before_vap->va_mtime), tl);
94360786Sps		tl += 2;
944161478Sdelphij		txdr_nfsv3time(&(before_vap->va_ctime), tl);
94560786Sps	}
94660786Sps	*bposp = bpos;
947172471Sdelphij	*mbp = mb;
94860786Sps	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
94960786Sps}
95060786Sps
95160786Spsvoid
952161478Sdelphijnfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
95360786Sps    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
95460786Sps{
955161478Sdelphij	struct mbuf *mb = *mbp;
956161478Sdelphij	char *bpos = *bposp;
957161478Sdelphij	u_int32_t *tl;
958161478Sdelphij	struct nfs_fattr *fp;
959161478Sdelphij
96060786Sps	if (after_ret) {
961161478Sdelphij		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
96260786Sps		*tl = nfsrv_nfs_false;
963161478Sdelphij	} else {
964161478Sdelphij		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
965161478Sdelphij		*tl++ = nfsrv_nfs_true;
966161478Sdelphij		fp = (struct nfs_fattr *)tl;
967161478Sdelphij		nfsm_srvfattr(nfsd, after_vap, fp);
968161478Sdelphij	}
969161478Sdelphij	*mbp = mb;
97060786Sps	*bposp = bpos;
971161478Sdelphij}
97260786Sps
973161478Sdelphijvoid
974161478Sdelphijnfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
97560786Sps    struct nfs_fattr *fp)
976161478Sdelphij{
977161478Sdelphij
978161478Sdelphij	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
979161478Sdelphij	fp->fa_uid = txdr_unsigned(vap->va_uid);
980161478Sdelphij	fp->fa_gid = txdr_unsigned(vap->va_gid);
981161478Sdelphij	if (nfsd->nd_flag & ND_NFSV3) {
982161478Sdelphij		fp->fa_type = vtonfsv3_type(vap->va_type);
983161478Sdelphij		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
984161478Sdelphij		txdr_hyper(vap->va_size, &fp->fa3_size);
985161478Sdelphij		txdr_hyper(vap->va_bytes, &fp->fa3_used);
986161478Sdelphij		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
987161478Sdelphij		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
988161478Sdelphij		fp->fa3_fsid.nfsuquad[0] = 0;
989161478Sdelphij		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
990161478Sdelphij		fp->fa3_fileid.nfsuquad[0] = 0;
99160786Sps		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
99260786Sps		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
99360786Sps		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
99460786Sps		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
99560786Sps	} else {
99660786Sps		fp->fa_type = vtonfsv2_type(vap->va_type);
997195941Sdelphij		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
99860786Sps		fp->fa2_size = txdr_unsigned(vap->va_size);
999195941Sdelphij		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
100060786Sps		if (vap->va_type == VFIFO)
1001161478Sdelphij			fp->fa2_rdev = 0xffffffff;
1002161478Sdelphij		else
100360786Sps			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
100460786Sps		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
100560786Sps		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
100660786Sps		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
100760786Sps		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
100860786Sps		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1009161478Sdelphij		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
101060786Sps	}
101160786Sps}
101260786Sps
101360786Sps/*
101460786Sps * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
101560786Sps * 	- look up fsid in mount list (if not found ret error)
101660786Sps *	- get vp and export rights by calling VFS_FHTOVP()
1017161478Sdelphij *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1018161478Sdelphij *	- if not lockflag unlock it with VOP_UNLOCK()
1019161478Sdelphij */
1020161478Sdelphijint
1021161478Sdelphijnfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1022161478Sdelphij    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1023161478Sdelphij    int *rdonlyp, int pubflag)
1024161478Sdelphij{
1025161478Sdelphij	struct thread *td = curthread; /* XXX */
1026161478Sdelphij	struct mount *mp;
1027161478Sdelphij	int i;
102860786Sps	struct ucred *credanon;
102960786Sps	int error, exflags;
103060786Sps#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1031170259Sdelphij	struct sockaddr_int *saddr;
1032170259Sdelphij#endif
1033170259Sdelphij
1034170259Sdelphij	*vpp = NULL;
1035170259Sdelphij
1036170259Sdelphij	if (nfs_ispublicfh(fhp)) {
1037170259Sdelphij		if (!pubflag || !nfs_pub.np_valid)
1038170259Sdelphij			return (ESTALE);
1039170259Sdelphij		fhp = &nfs_pub.np_handle;
104060786Sps	}
1041191930Sdelphij
104260786Sps	mp = vfs_getvfs(&fhp->fh_fsid);
104360786Sps	if (!mp)
104460786Sps		return (ESTALE);
104560786Sps	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1046173685Sdelphij	if (error)
1047195941Sdelphij		return (error);
1048173685Sdelphij	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1049173685Sdelphij	if (error)
1050191930Sdelphij		return (error);
1051191930Sdelphij#ifdef MNT_EXNORESPORT
1052191930Sdelphij	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1053191930Sdelphij		saddr = (struct sockaddr_in *)nam;
1054191930Sdelphij		if ((saddr->sin_family == AF_INET ||
1055191930Sdelphij		     saddr->sin_family == AF_INET6) &&
1056195941Sdelphij	/* same code for INET and INET6: sin*_port at same offet */
1057195941Sdelphij		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1058195941Sdelphij			vput(*vpp);
1059195941Sdelphij			*vpp = NULL;
1060195941Sdelphij			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1061195941Sdelphij		}
1062173685Sdelphij	}
1063195941Sdelphij#endif
1064173685Sdelphij	/*
1065173685Sdelphij	 * Check/setup credentials.
1066173685Sdelphij	 */
106760786Sps	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
106860786Sps		cred->cr_uid = credanon->cr_uid;
106960786Sps		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1070191930Sdelphij			cred->cr_groups[i] = credanon->cr_groups[i];
107189019Sps		cred->cr_ngroups = i;
1072191930Sdelphij	}
1073191930Sdelphij	if (exflags & MNT_EXRDONLY)
1074191930Sdelphij		*rdonlyp = 1;
1075191930Sdelphij	else
1076191930Sdelphij		*rdonlyp = 0;
1077191930Sdelphij
1078191930Sdelphij	nfsrv_object_create(*vpp);
1079191930Sdelphij
1080191930Sdelphij	if (!lockflag)
108160786Sps		VOP_UNLOCK(*vpp, 0, td);
108260786Sps	return (0);
108360786Sps}
108460786Sps
108560786Sps
108660786Sps/*
108760786Sps * WebNFS: check if a filehandle is a public filehandle. For v3, this
108860786Sps * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
108960786Sps * transformed this to all zeroes in both cases, so check for it.
109060786Sps */
109160786Spsint
109260786Spsnfs_ispublicfh(fhandle_t *fhp)
109360786Sps{
109460786Sps	char *cp = (char *)fhp;
109560786Sps	int i;
109660786Sps
109760786Sps	for (i = 0; i < NFSX_V3FH; i++)
109860786Sps		if (*cp++ != 0)
1099161478Sdelphij			return (FALSE);
1100161478Sdelphij	return (TRUE);
1101161478Sdelphij}
1102161478Sdelphij
1103161478Sdelphij/*
1104161478Sdelphij * This function compares two net addresses by family and returns TRUE
1105161478Sdelphij * if they are the same host.
1106161478Sdelphij * If there is any doubt, return FALSE.
1107161478Sdelphij * The AF_INET family is handled as a special case so that address mbufs
1108161478Sdelphij * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1109161478Sdelphij */
1110161478Sdelphijint
111160786Spsnetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
111260786Sps{
111360786Sps	struct sockaddr_in *inetaddr;
1114161478Sdelphij
111560786Sps	switch (family) {
111660786Sps	case AF_INET:
111760786Sps		inetaddr = (struct sockaddr_in *)nam;
111860786Sps		if (inetaddr->sin_family == AF_INET &&
111960786Sps		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
112060786Sps			return (1);
112160786Sps		break;
112260786Sps#ifdef INET6
112360786Sps	case AF_INET6:
112460786Sps	{
112560786Sps		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
112660786Sps
112760786Sps		inet6addr1 = (struct sockaddr_in6 *)nam;
112860786Sps		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
112960786Sps	/* XXX - should test sin6_scope_id ? */
113060786Sps		if (inet6addr1->sin6_family == AF_INET6 &&
113160786Sps		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
113260786Sps				       &inet6addr2->sin6_addr))
1133170259Sdelphij			return (1);
113460786Sps		break;
113560786Sps	}
1136170259Sdelphij#endif
113760786Sps	default:
113889019Sps		break;
113960786Sps	};
114060786Sps	return (0);
114160786Sps}
114260786Sps
114360786Sps/*
114460786Sps * Map errnos to NFS error numbers. For Version 3 also filter out error
114560786Sps * numbers not specified for the associated procedure.
114689019Sps */
114760786Spsint
114860786Spsnfsrv_errmap(struct nfsrv_descript *nd, int err)
1149161478Sdelphij{
115060786Sps	short *defaulterrp, *errp;
115160786Sps	int e;
115260786Sps
115360786Sps	if (nd->nd_flag & ND_NFSV3) {
115489019Sps	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
115560786Sps		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
115689019Sps		while (*++errp) {
115789019Sps			if (*errp == err)
115889019Sps				return (err);
115989019Sps			else if (*errp > err)
116089019Sps				break;
116189019Sps		}
116289019Sps		return ((int)*defaulterrp);
116389019Sps	    } else
116489019Sps		return (err & 0xffff);
116560786Sps	}
116689019Sps	e = 0;
116760786Sps	if (err <= ELAST)
116860786Sps		e = nfsrv_v2errmap[err - 1];
116989019Sps	if (e != 0)
117060786Sps		return (e);
117160786Sps	return (NFSERR_IO);
1172170259Sdelphij}
1173170259Sdelphij
117460786Spsint
117560786Spsnfsrv_object_create(struct vnode *vp)
117660786Sps{
117760786Sps
117860786Sps	if (vp == NULL || vp->v_type != VREG)
117960786Sps		return (1);
118060786Sps	return (vfs_object_create(vp, curthread, curthread->td_ucred));
118160786Sps}
1182170259Sdelphij
118360786Sps/*
118460786Sps * Sort the group list in increasing numerical order.
1185170259Sdelphij * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
118660786Sps *  that used to be here.)
118789019Sps */
118860786Spsvoid
118960786Spsnfsrvw_sort(gid_t *list, int num)
119060786Sps{
119160786Sps	int i, j;
119260786Sps	gid_t v;
119360786Sps
119460786Sps	/* Insertion sort. */
119589019Sps	for (i = 1; i < num; i++) {
119689019Sps		v = list[i];
119760786Sps		/* find correct slot for value v, moving others up */
119860786Sps		for (j = i; --j >= 0 && v < list[j];)
119960786Sps			list[j + 1] = list[j];
1200161478Sdelphij		list[j + 1] = v;
120160786Sps	}
120260786Sps}
120360786Sps
120460786Sps/*
120560786Sps * copy credentials making sure that the result can be compared with bcmp().
120660786Sps */
120760786Spsvoid
120860786Spsnfsrv_setcred(struct ucred *incred, struct ucred *outcred)
120960786Sps{
121060786Sps	int i;
121160786Sps
121260786Sps	bzero((caddr_t)outcred, sizeof (struct ucred));
121360786Sps	outcred->cr_ref = 1;
121460786Sps	outcred->cr_uid = incred->cr_uid;
121560786Sps	outcred->cr_ngroups = incred->cr_ngroups;
121660786Sps	for (i = 0; i < incred->cr_ngroups; i++)
121760786Sps		outcred->cr_groups[i] = incred->cr_groups[i];
121860786Sps	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
121989019Sps}
122060786Sps
122189019Sps/*
122289019Sps * Helper functions for macros.
122389019Sps */
122489019Sps
122589019Spsvoid
122689019Spsnfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
122789019Sps{
122889019Sps	u_int32_t *tl;
122989019Sps
123089019Sps	if (v3) {
123189019Sps		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
123289019Sps		*tl++ = txdr_unsigned(NFSX_V3FH);
123360786Sps		bcopy(f, tl, NFSX_V3FH);
123489019Sps	} else {
123560786Sps		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1236149487Stjr		bcopy(f, tl, NFSX_V2FH);
1237149487Stjr	}
123889019Sps}
123989019Sps
124089019Spsvoid
124160786Spsnfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
124289019Sps{
124360786Sps	u_int32_t *tl;
124460786Sps
124589019Sps	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1246170259Sdelphij	*tl++ = nfsrv_nfs_true;
1247170259Sdelphij	*tl++ = txdr_unsigned(NFSX_V3FH);
124860786Sps	bcopy(f, tl, NFSX_V3FH);
124960786Sps}
1250
1251int
1252nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1253{
1254	u_int32_t *tl;
1255
1256	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1257	if (tl == NULL)
1258		return EBADRPC;
1259	*s = fxdr_unsigned(int32_t, *tl);
1260	if (*s > m || *s <= 0)
1261		return EBADRPC;
1262	return 0;
1263}
1264
1265int
1266nfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos)
1267{
1268	u_int32_t *tl;
1269
1270	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1271	if (tl == NULL)
1272		return EBADRPC;
1273	*s = fxdr_unsigned(int32_t, *tl);
1274	if (*s > NFS_MAXNAMLEN)
1275		return NFSERR_NAMETOL;
1276	if (*s <= 0)
1277		return EBADRPC;
1278	return 0;
1279}
1280
1281void
1282nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1283    char **bp, char **be, caddr_t bpos)
1284{
1285	struct mbuf *nmp;
1286
1287	if (*bp >= *be) {
1288		if (*mp == mb)
1289			(*mp)->m_len += *bp - bpos;
1290		MGET(nmp, M_TRYWAIT, MT_DATA);
1291		MCLGET(nmp, M_TRYWAIT);
1292		nmp->m_len = NFSMSIZ(nmp);
1293		(*mp)->m_next = nmp;
1294		*mp = nmp;
1295		*bp = mtod(*mp, caddr_t);
1296		*be = *bp + (*mp)->m_len;
1297	}
1298	*tl = (u_int32_t *)*bp;
1299}
1300
1301int
1302nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1303    caddr_t *dpos)
1304{
1305	u_int32_t *tl;
1306	int fhlen;
1307
1308	if (nfsd->nd_flag & ND_NFSV3) {
1309		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1310		if (tl == NULL)
1311			return EBADRPC;
1312		fhlen = fxdr_unsigned(int, *tl);
1313		if (fhlen != 0 && fhlen != NFSX_V3FH)
1314			return EBADRPC;
1315	} else {
1316		fhlen = NFSX_V2FH;
1317	}
1318	if (fhlen != 0) {
1319		tl = nfsm_dissect_xx(fhlen, md, dpos);
1320		if (tl == NULL)
1321			return EBADRPC;
1322		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1323	} else {
1324		bzero((caddr_t)(f), NFSX_V3FH);
1325	}
1326	return 0;
1327}
1328
1329int
1330nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1331{
1332	u_int32_t *tl;
1333
1334	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1335	if (tl == NULL)
1336		return EBADRPC;
1337	if (*tl == nfsrv_nfs_true) {
1338		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1339		if (tl == NULL)
1340			return EBADRPC;
1341		(a)->va_mode = nfstov_mode(*tl);
1342	}
1343	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1344	if (tl == NULL)
1345		return EBADRPC;
1346	if (*tl == nfsrv_nfs_true) {
1347		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1348		if (tl == NULL)
1349			return EBADRPC;
1350		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
1351	}
1352	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1353	if (tl == NULL)
1354		return EBADRPC;
1355	if (*tl == nfsrv_nfs_true) {
1356		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1357		if (tl == NULL)
1358			return EBADRPC;
1359		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
1360	}
1361	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1362	if (tl == NULL)
1363		return EBADRPC;
1364	if (*tl == nfsrv_nfs_true) {
1365		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1366		if (tl == NULL)
1367			return EBADRPC;
1368		(a)->va_size = fxdr_hyper(tl);
1369	}
1370	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1371	if (tl == NULL)
1372		return EBADRPC;
1373	switch (fxdr_unsigned(int, *tl)) {
1374	case NFSV3SATTRTIME_TOCLIENT:
1375		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1376		if (tl == NULL)
1377			return EBADRPC;
1378		fxdr_nfsv3time(tl, &(a)->va_atime);
1379		break;
1380	case NFSV3SATTRTIME_TOSERVER:
1381		getnanotime(&(a)->va_atime);
1382		break;
1383	}
1384	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1385	if (tl == NULL)
1386		return EBADRPC;
1387	switch (fxdr_unsigned(int, *tl)) {
1388	case NFSV3SATTRTIME_TOCLIENT:
1389		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1390		if (tl == NULL)
1391			return EBADRPC;
1392		fxdr_nfsv3time(tl, &(a)->va_mtime);
1393		break;
1394	case NFSV3SATTRTIME_TOSERVER:
1395		getnanotime(&(a)->va_mtime);
1396		break;
1397	}
1398	return 0;
1399}
1400