nfs_srvsubs.c revision 102236
162587Sitojun/*
295023Ssuz * Copyright (c) 1989, 1993
362587Sitojun *	The Regents of the University of California.  All rights reserved.
4139826Simp *
553541Sshin * This code is derived from software contributed to Berkeley by
653541Sshin * Rick Macklem at The University of Guelph.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. All advertising materials mentioning features or use of this software
1753541Sshin *    must display the following acknowledgement:
1853541Sshin *	This product includes software developed by the University of
1953541Sshin *	California, Berkeley and its contributors.
2053541Sshin * 4. Neither the name of the University nor the names of its contributors
2153541Sshin *    may be used to endorse or promote products derived from this software
2253541Sshin *    without specific prior written permission.
2353541Sshin *
2453541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2553541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2653541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2753541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2853541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2953541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3053541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3153541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3253541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3362587Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3462587Sitojun * SUCH DAMAGE.
35142215Sglebius *
36142215Sglebius *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
3755009Sshin * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 102236 2002-08-21 19:28:44Z phk $
3853541Sshin */
3953541Sshin
4053541Sshin#include <sys/cdefs.h>
4153541Sshin__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 102236 2002-08-21 19:28:44Z phk $");
4253541Sshin
4353541Sshin/*
4453541Sshin * These functions support the macros and help fiddle mbuf chains for
4553541Sshin * the nfs op functions. They do things like create the rpc header and
4653541Sshin * copy data between mbuf chains and uio lists.
4753541Sshin */
4853541Sshin
4978064Sume#include "opt_inet6.h"
5053541Sshin
5153541Sshin#include <sys/param.h>
5253541Sshin#include <sys/systm.h>
5353541Sshin#include <sys/kernel.h>
54147306Sbrooks#include <sys/bio.h>
5553541Sshin#include <sys/buf.h>
5653541Sshin#include <sys/proc.h>
5753541Sshin#include <sys/mount.h>
5853541Sshin#include <sys/vnode.h>
5953541Sshin#include <sys/namei.h>
60151477Ssuz#include <sys/mbuf.h>
6162587Sitojun#include <sys/socket.h>
6253541Sshin#include <sys/stat.h>
63148385Sume#include <sys/malloc.h>
6453541Sshin#include <sys/module.h>
6562587Sitojun#include <sys/sysent.h>
6653541Sshin#include <sys/syscall.h>
67142215Sglebius#include <sys/sysproto.h>
68142215Sglebius
69142215Sglebius#include <vm/vm.h>
70142215Sglebius#include <vm/vm_object.h>
7162587Sitojun#include <vm/vm_extern.h>
7253541Sshin#include <vm/uma.h>
7362587Sitojun
7462587Sitojun#include <nfs/rpcv2.h>
7578064Sume#include <nfs/nfsproto.h>
7678064Sume#include <nfsserver/nfs.h>
7762587Sitojun#include <nfs/xdr_subs.h>
7862587Sitojun#include <nfsserver/nfsm_subs.h>
7962587Sitojun
8062587Sitojun#include <netinet/in.h>
8153541Sshin
8262587Sitojun/*
8362587Sitojun * Data items converted to xdr at startup, since they are constant
8453541Sshin * This is kinda hokey, but may save a little time doing byte swaps
8553541Sshin */
86108470Sschweikhu_int32_t nfsrv_nfs_xdrneg1;
8753541Sshinu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
8853541Sshin	nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
89148987Sume	nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
9053541Sshinu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
9153541Sshin
9253541Sshin/* And other global data */
9353541Sshinstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
9453541Sshin				 NFNON, NFCHR, NFNON };
9553541Sshin#define vtonfsv2_type(a)	txdr_unsigned(nfsv2_type[((int32_t)(a))])
9653541Sshin#define vtonfsv3_mode(m)	txdr_unsigned((m) & ALLPERMS)
9753541Sshin
9862587Sitojunint nfsrv_ticks;
9953541Sshin
10053541Sshinstruct nfssvc_sockhead nfssvc_sockhead;
10162587Sitojunint nfssvc_sockhead_flag;
10253541Sshinstruct nfsd_head nfsd_head;
10353541Sshinint nfsd_head_flag;
104142215Sglebius
10553541Sshinstatic int nfs_prev_nfssvc_sy_narg;
10653541Sshinstatic sy_call_t *nfs_prev_nfssvc_sy_call;
10753541Sshin
10853541Sshin/*
10962587Sitojun * Mapping of old NFS Version 2 RPC numbers to generic numbers.
110165118Sbz */
11153541Sshinint nfsrv_nfsv3_procid[NFS_NPROCS] = {
11278064Sume	NFSPROC_NULL,
11378064Sume	NFSPROC_GETATTR,
11478064Sume	NFSPROC_SETATTR,
11578064Sume	NFSPROC_NOOP,
11678064Sume	NFSPROC_LOOKUP,
11778064Sume	NFSPROC_READLINK,
11878064Sume	NFSPROC_READ,
11978064Sume	NFSPROC_NOOP,
12078064Sume	NFSPROC_WRITE,
12178064Sume	NFSPROC_CREATE,
12278064Sume	NFSPROC_REMOVE,
12378064Sume	NFSPROC_RENAME,
124148385Sume	NFSPROC_LINK,
125148385Sume	NFSPROC_SYMLINK,
12678064Sume	NFSPROC_MKDIR,
12753541Sshin	NFSPROC_RMDIR,
12878064Sume	NFSPROC_READDIR,
12978064Sume	NFSPROC_FSSTAT,
130165118Sbz	NFSPROC_NOOP,
131165118Sbz	NFSPROC_NOOP,
13278064Sume	NFSPROC_NOOP,
13353541Sshin	NFSPROC_NOOP,
13453541Sshin	NFSPROC_NOOP,
13553541Sshin};
136148987Sume
137120941Sume/*
13895023Ssuz * and the reverse mapping from generic to Version 2 procedure numbers
139120941Sume */
140120941Sumeint nfsrvv2_procid[NFS_NPROCS] = {
141120941Sume	NFSV2PROC_NULL,
14295023Ssuz	NFSV2PROC_GETATTR,
14353541Sshin	NFSV2PROC_SETATTR,
14478064Sume	NFSV2PROC_LOOKUP,
145120941Sume	NFSV2PROC_NOOP,
14653541Sshin	NFSV2PROC_READLINK,
14753541Sshin	NFSV2PROC_READ,
14853541Sshin	NFSV2PROC_WRITE,
14953541Sshin	NFSV2PROC_CREATE,
15053541Sshin	NFSV2PROC_MKDIR,
15178064Sume	NFSV2PROC_SYMLINK,
15253541Sshin	NFSV2PROC_CREATE,
15353541Sshin	NFSV2PROC_REMOVE,
15453541Sshin	NFSV2PROC_RMDIR,
15553541Sshin	NFSV2PROC_RENAME,
15653541Sshin	NFSV2PROC_LINK,
15753541Sshin	NFSV2PROC_READDIR,
15878064Sume	NFSV2PROC_NOOP,
15978064Sume	NFSV2PROC_STATFS,
16078064Sume	NFSV2PROC_NOOP,
16178064Sume	NFSV2PROC_NOOP,
16253541Sshin	NFSV2PROC_NOOP,
16353541Sshin	NFSV2PROC_NOOP,
16453541Sshin};
16595023Ssuz
16653541Sshin/*
16753541Sshin * Maps errno values to nfs error numbers.
168120941Sume * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
16953541Sshin * specifically defined in RFC 1094.
17078064Sume */
17178064Sumestatic u_char nfsrv_v2errmap[ELAST] = {
17253541Sshin  NFSERR_PERM,	NFSERR_NOENT,	0,		0,		0,
17353541Sshin  NFSERR_NXIO,	0,		0,		0,		0,
17453541Sshin  0,		0,		NFSERR_ACCES,	0,		0,
17553541Sshin  0,		NFSERR_EXIST,	0,		NFSERR_NODEV,	NFSERR_NOTDIR,
17653541Sshin  NFSERR_ISDIR,	0,		0,		0,		0,
17753541Sshin  0,		NFSERR_FBIG,	NFSERR_NOSPC,	0,		NFSERR_ROFS,
17853541Sshin  0,		0,		0,		0,		0,
17953541Sshin  0,		0,		0,		0,		0,
18053541Sshin  0,		0,		0,		0,		0,
18153541Sshin  0,		0,		0,		0,		0,
18253541Sshin  0,		0,		0,		0,		0,
18353541Sshin  0,		0,		0,		0,		0,
18453541Sshin  0,		0,		NFSERR_NAMETOL,	0,		0,
18553541Sshin  NFSERR_NOTEMPTY, 0,		0,		NFSERR_DQUOT,	NFSERR_STALE,
18653541Sshin  0
18753541Sshin};
18853541Sshin
18953541Sshin/*
19053541Sshin * Maps errno values to nfs error numbers.
19153541Sshin * Although it is not obvious whether or not NFS clients really care if
19253541Sshin * a returned error value is in the specified list for the procedure, the
19353541Sshin * safest thing to do is filter them appropriately. For Version 2, the
19453541Sshin * X/Open XNFS document is the only specification that defines error values
19553541Sshin * for each RPC (The RFC simply lists all possible error values for all RPCs),
19653541Sshin * so I have decided to not do this for Version 2.
197142215Sglebius * The first entry is the default error return and the rest are the valid
198142215Sglebius * errors for that RPC in increasing numeric order.
199142215Sglebius */
200151465Ssuzstatic short nfsv3err_null[] = {
201142215Sglebius	0,
202142215Sglebius	0,
20353541Sshin};
204142215Sglebius
20553541Sshinstatic short nfsv3err_getattr[] = {
20653541Sshin	NFSERR_IO,
207151465Ssuz	NFSERR_IO,
20853541Sshin	NFSERR_STALE,
20953541Sshin	NFSERR_BADHANDLE,
210121765Ssam	NFSERR_SERVERFAULT,
21153541Sshin	0,
21253541Sshin};
21353541Sshin
21453541Sshinstatic short nfsv3err_setattr[] = {
21553541Sshin	NFSERR_IO,
21653541Sshin	NFSERR_PERM,
21753541Sshin	NFSERR_IO,
218121765Ssam	NFSERR_ACCES,
219121765Ssam	NFSERR_INVAL,
220121765Ssam	NFSERR_NOSPC,
221121765Ssam	NFSERR_ROFS,
222121765Ssam	NFSERR_DQUOT,
22353541Sshin	NFSERR_STALE,
22462587Sitojun	NFSERR_BADHANDLE,
22553541Sshin	NFSERR_NOT_SYNC,
22662587Sitojun	NFSERR_SERVERFAULT,
22762587Sitojun	0,
22862587Sitojun};
22953541Sshin
23062587Sitojunstatic short nfsv3err_lookup[] = {
23162587Sitojun	NFSERR_IO,
23253541Sshin	NFSERR_NOENT,
23353541Sshin	NFSERR_IO,
234151479Ssuz	NFSERR_ACCES,
23553541Sshin	NFSERR_NOTDIR,
23678064Sume	NFSERR_NAMETOL,
23753541Sshin	NFSERR_STALE,
23853541Sshin	NFSERR_BADHANDLE,
23953541Sshin	NFSERR_SERVERFAULT,
24062587Sitojun	0,
24153541Sshin};
24253541Sshin
24353541Sshinstatic short nfsv3err_access[] = {
24453541Sshin	NFSERR_IO,
24553541Sshin	NFSERR_IO,
24662587Sitojun	NFSERR_STALE,
24753541Sshin	NFSERR_BADHANDLE,
24853541Sshin	NFSERR_SERVERFAULT,
249120941Sume	0,
25053541Sshin};
251165118Sbz
252120941Sumestatic short nfsv3err_readlink[] = {
25378064Sume	NFSERR_IO,
25453541Sshin	NFSERR_IO,
25553541Sshin	NFSERR_ACCES,
25653541Sshin	NFSERR_INVAL,
257120941Sume	NFSERR_STALE,
258165118Sbz	NFSERR_BADHANDLE,
25962587Sitojun	NFSERR_NOTSUPP,
26053541Sshin	NFSERR_SERVERFAULT,
26153541Sshin	0,
26253541Sshin};
26353541Sshin
26453541Sshinstatic short nfsv3err_read[] = {
26553541Sshin	NFSERR_IO,
26653541Sshin	NFSERR_IO,
26753541Sshin	NFSERR_NXIO,
26853541Sshin	NFSERR_ACCES,
26953541Sshin	NFSERR_INVAL,
27053541Sshin	NFSERR_STALE,
27153541Sshin	NFSERR_BADHANDLE,
27253541Sshin	NFSERR_SERVERFAULT,
27353541Sshin	0,
27453541Sshin};
27553541Sshin
27653541Sshinstatic short nfsv3err_write[] = {
277148987Sume	NFSERR_IO,
27853541Sshin	NFSERR_IO,
27953541Sshin	NFSERR_ACCES,
28053541Sshin	NFSERR_INVAL,
28153541Sshin	NFSERR_FBIG,
28253541Sshin	NFSERR_NOSPC,
28353541Sshin	NFSERR_ROFS,
28453541Sshin	NFSERR_DQUOT,
28562587Sitojun	NFSERR_STALE,
28653541Sshin	NFSERR_BADHANDLE,
28753541Sshin	NFSERR_SERVERFAULT,
28853541Sshin	0,
28953541Sshin};
29053541Sshin
29153541Sshinstatic short nfsv3err_create[] = {
29253541Sshin	NFSERR_IO,
29353541Sshin	NFSERR_IO,
29453541Sshin	NFSERR_ACCES,
29553541Sshin	NFSERR_EXIST,
29653541Sshin	NFSERR_NOTDIR,
297148385Sume	NFSERR_NOSPC,
298148385Sume	NFSERR_ROFS,
299148385Sume	NFSERR_NAMETOL,
300148385Sume	NFSERR_DQUOT,
301148385Sume	NFSERR_STALE,
302148385Sume	NFSERR_BADHANDLE,
303120941Sume	NFSERR_NOTSUPP,
304120941Sume	NFSERR_SERVERFAULT,
305120941Sume	0,
30662587Sitojun};
30753541Sshin
30853541Sshinstatic short nfsv3err_mkdir[] = {
309120941Sume	NFSERR_IO,
310120941Sume	NFSERR_IO,
31153541Sshin	NFSERR_ACCES,
31253541Sshin	NFSERR_EXIST,
313120941Sume	NFSERR_NOTDIR,
314120941Sume	NFSERR_NOSPC,
315120941Sume	NFSERR_ROFS,
31662587Sitojun	NFSERR_NAMETOL,
31762587Sitojun	NFSERR_DQUOT,
31853541Sshin	NFSERR_STALE,
31953541Sshin	NFSERR_BADHANDLE,
32053541Sshin	NFSERR_NOTSUPP,
321165118Sbz	NFSERR_SERVERFAULT,
322165118Sbz	0,
323165118Sbz};
324165118Sbz
325165118Sbzstatic short nfsv3err_symlink[] = {
326165118Sbz	NFSERR_IO,
32778064Sume	NFSERR_IO,
32862587Sitojun	NFSERR_ACCES,
32953541Sshin	NFSERR_EXIST,
33053541Sshin	NFSERR_NOTDIR,
33153541Sshin	NFSERR_NOSPC,
332108470Sschweikh	NFSERR_ROFS,
33353541Sshin	NFSERR_NAMETOL,
33453541Sshin	NFSERR_DQUOT,
33553541Sshin	NFSERR_STALE,
33653541Sshin	NFSERR_BADHANDLE,
33753541Sshin	NFSERR_NOTSUPP,
338148987Sume	NFSERR_SERVERFAULT,
33953541Sshin	0,
34053541Sshin};
34153541Sshin
34253541Sshinstatic short nfsv3err_mknod[] = {
34378064Sume	NFSERR_IO,
34453541Sshin	NFSERR_IO,
345148987Sume	NFSERR_ACCES,
34653541Sshin	NFSERR_EXIST,
34753541Sshin	NFSERR_NOTDIR,
34853541Sshin	NFSERR_NOSPC,
34953541Sshin	NFSERR_ROFS,
350148385Sume	NFSERR_NAMETOL,
35153541Sshin	NFSERR_DQUOT,
35253541Sshin	NFSERR_STALE,
35362587Sitojun	NFSERR_BADHANDLE,
35453541Sshin	NFSERR_NOTSUPP,
355148385Sume	NFSERR_SERVERFAULT,
356120941Sume	NFSERR_BADTYPE,
357148385Sume	0,
358148385Sume};
35953541Sshin
36053541Sshinstatic short nfsv3err_remove[] = {
36153541Sshin	NFSERR_IO,
36262587Sitojun	NFSERR_NOENT,
36362587Sitojun	NFSERR_IO,
36462587Sitojun	NFSERR_ACCES,
36562587Sitojun	NFSERR_NOTDIR,
36662587Sitojun	NFSERR_ROFS,
36762587Sitojun	NFSERR_NAMETOL,
36862587Sitojun	NFSERR_STALE,
36962587Sitojun	NFSERR_BADHANDLE,
37053541Sshin	NFSERR_SERVERFAULT,
37162587Sitojun	0,
37253541Sshin};
373111119Simp
37462587Sitojunstatic short nfsv3err_rmdir[] = {
375111119Simp	NFSERR_IO,
37662587Sitojun	NFSERR_NOENT,
37762587Sitojun	NFSERR_IO,
37862587Sitojun	NFSERR_ACCES,
37962587Sitojun	NFSERR_EXIST,
38062587Sitojun	NFSERR_NOTDIR,
38162587Sitojun	NFSERR_INVAL,
38262587Sitojun	NFSERR_ROFS,
38378064Sume	NFSERR_NAMETOL,
38462587Sitojun	NFSERR_NOTEMPTY,
38553541Sshin	NFSERR_STALE,
38653541Sshin	NFSERR_BADHANDLE,
38753541Sshin	NFSERR_NOTSUPP,
38853541Sshin	NFSERR_SERVERFAULT,
38953541Sshin	0,
39053541Sshin};
39153541Sshin
39253541Sshinstatic short nfsv3err_rename[] = {
39353541Sshin	NFSERR_IO,
39495023Ssuz	NFSERR_NOENT,
39553541Sshin	NFSERR_IO,
39653541Sshin	NFSERR_ACCES,
39753541Sshin	NFSERR_EXIST,
39853541Sshin	NFSERR_XDEV,
39962587Sitojun	NFSERR_NOTDIR,
40062587Sitojun	NFSERR_ISDIR,
40153541Sshin	NFSERR_INVAL,
40253541Sshin	NFSERR_NOSPC,
40353541Sshin	NFSERR_ROFS,
40453541Sshin	NFSERR_MLINK,
40553541Sshin	NFSERR_NAMETOL,
40653541Sshin	NFSERR_NOTEMPTY,
40753541Sshin	NFSERR_DQUOT,
408148385Sume	NFSERR_STALE,
40953541Sshin	NFSERR_BADHANDLE,
41053541Sshin	NFSERR_NOTSUPP,
41153541Sshin	NFSERR_SERVERFAULT,
41253541Sshin	0,
413148385Sume};
414148385Sume
41553541Sshinstatic short nfsv3err_link[] = {
41653541Sshin	NFSERR_IO,
41753541Sshin	NFSERR_IO,
41853541Sshin	NFSERR_ACCES,
41953541Sshin	NFSERR_EXIST,
42053541Sshin	NFSERR_XDEV,
42153541Sshin	NFSERR_NOTDIR,
42253541Sshin	NFSERR_INVAL,
42353541Sshin	NFSERR_NOSPC,
42453541Sshin	NFSERR_ROFS,
42553541Sshin	NFSERR_MLINK,
42653541Sshin	NFSERR_NAMETOL,
42753541Sshin	NFSERR_DQUOT,
42853541Sshin	NFSERR_STALE,
42953541Sshin	NFSERR_BADHANDLE,
430148385Sume	NFSERR_NOTSUPP,
43153541Sshin	NFSERR_SERVERFAULT,
43295023Ssuz	0,
433148385Sume};
43453541Sshin
43553541Sshinstatic short nfsv3err_readdir[] = {
436148987Sume	NFSERR_IO,
437148987Sume	NFSERR_IO,
438148987Sume	NFSERR_ACCES,
439148987Sume	NFSERR_NOTDIR,
44053541Sshin	NFSERR_STALE,
44153541Sshin	NFSERR_BADHANDLE,
44253541Sshin	NFSERR_BAD_COOKIE,
443148385Sume	NFSERR_TOOSMALL,
44453541Sshin	NFSERR_SERVERFAULT,
445148385Sume	0,
446148385Sume};
447148385Sume
448148385Sumestatic short nfsv3err_readdirplus[] = {
44953541Sshin	NFSERR_IO,
450148385Sume	NFSERR_IO,
451148385Sume	NFSERR_ACCES,
452148385Sume	NFSERR_NOTDIR,
453148385Sume	NFSERR_STALE,
454148385Sume	NFSERR_BADHANDLE,
455148385Sume	NFSERR_BAD_COOKIE,
456148385Sume	NFSERR_NOTSUPP,
457148385Sume	NFSERR_TOOSMALL,
458148385Sume	NFSERR_SERVERFAULT,
459148385Sume	0,
460148385Sume};
461165118Sbz
462148385Sumestatic short nfsv3err_fsstat[] = {
463148385Sume	NFSERR_IO,
464148385Sume	NFSERR_IO,
465165118Sbz	NFSERR_STALE,
466165118Sbz	NFSERR_BADHANDLE,
467148385Sume	NFSERR_SERVERFAULT,
46853541Sshin	0,
46953541Sshin};
47053541Sshin
47153541Sshinstatic short nfsv3err_fsinfo[] = {
47253541Sshin	NFSERR_STALE,
47353541Sshin	NFSERR_STALE,
474148385Sume	NFSERR_BADHANDLE,
475148385Sume	NFSERR_SERVERFAULT,
476148385Sume	0,
47753541Sshin};
478148385Sume
479148385Sumestatic short nfsv3err_pathconf[] = {
48053541Sshin	NFSERR_STALE,
481148385Sume	NFSERR_STALE,
48253541Sshin	NFSERR_BADHANDLE,
48353541Sshin	NFSERR_SERVERFAULT,
48453541Sshin	0,
48553541Sshin};
48653541Sshin
487121315Sumestatic short nfsv3err_commit[] = {
48853541Sshin	NFSERR_IO,
48953541Sshin	NFSERR_IO,
49053541Sshin	NFSERR_STALE,
49153541Sshin	NFSERR_BADHANDLE,
49253541Sshin	NFSERR_SERVERFAULT,
49353541Sshin	0,
49453541Sshin};
49553541Sshin
49653541Sshinstatic short *nfsrv_v3errmap[] = {
49753541Sshin	nfsv3err_null,
49853541Sshin	nfsv3err_getattr,
49953541Sshin	nfsv3err_setattr,
50053541Sshin	nfsv3err_lookup,
50153541Sshin	nfsv3err_access,
50253541Sshin	nfsv3err_readlink,
50353541Sshin	nfsv3err_read,
50453541Sshin	nfsv3err_write,
50553541Sshin	nfsv3err_create,
506120941Sume	nfsv3err_mkdir,
50753541Sshin	nfsv3err_symlink,
50853541Sshin	nfsv3err_mknod,
50953541Sshin	nfsv3err_remove,
51053541Sshin	nfsv3err_rmdir,
51153541Sshin	nfsv3err_rename,
51253541Sshin	nfsv3err_link,
51353541Sshin	nfsv3err_readdir,
51453541Sshin	nfsv3err_readdirplus,
51553541Sshin	nfsv3err_fsstat,
51653541Sshin	nfsv3err_fsinfo,
51753541Sshin	nfsv3err_pathconf,
518120941Sume	nfsv3err_commit,
519120941Sume};
52053541Sshin
521151536Ssuz/*
522148385Sume * Called once to initialize data structures...
523148385Sume */
524148385Sumestatic int
525148385Sumenfsrv_modevent(module_t mod, int type, void *data)
526148385Sume{
527148385Sume
52853541Sshin	switch (type) {
529148385Sume	case MOD_LOAD:
530148385Sume		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
531148385Sume		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
532148385Sume		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
533148385Sume		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
534148385Sume		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
535148385Sume		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
536148385Sume		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
53753541Sshin		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
53853541Sshin		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
53953541Sshin		nfsrv_nfs_true = txdr_unsigned(TRUE);
54053541Sshin		nfsrv_nfs_false = txdr_unsigned(FALSE);
54153541Sshin		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
54253541Sshin		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
543148987Sume		if (nfsrv_ticks < 1)
54462587Sitojun			nfsrv_ticks = 1;
54562587Sitojun
54662587Sitojun		nfsrv_init(0);		/* Init server data structures */
54762587Sitojun		nfsrv_initcache();	/* Init the server request cache */
54853541Sshin
54953541Sshin		nfsrv_timer(0);
55053541Sshin
55153541Sshin		nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
55253541Sshin		sysent[SYS_nfssvc].sy_narg = 2;
55353541Sshin		nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
55453541Sshin		sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
55553541Sshin		break;
55662587Sitojun
55753541Sshin		case MOD_UNLOAD:
55862587Sitojun
55962587Sitojun		untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle);
56062587Sitojun		sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
56162587Sitojun		sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
56262587Sitojun		break;
56353541Sshin	}
56453541Sshin	return 0;
56553541Sshin}
56653541Sshinstatic moduledata_t nfsserver_mod = {
56753541Sshin	"nfsserver",
56853541Sshin	nfsrv_modevent,
56953541Sshin	NULL,
570165118Sbz};
57153541SshinDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
57253541Sshin
57378064Sume/* So that loader and kldload(2) can find us, wherever we are.. */
57478064SumeMODULE_VERSION(nfsserver, 1);
575165118Sbz
576165118Sbz/*
57778064Sume * Set up nameidata for a lookup() call and do it.
57862587Sitojun *
57962587Sitojun * If pubflag is set, this call is done for a lookup operation on the
58062587Sitojun * public filehandle. In that case we allow crossing mountpoints and
58162587Sitojun * absolute pathnames. However, the caller is expected to check that
58262587Sitojun * the lookup result is within the public fs, and deny access if
58362587Sitojun * it is not.
58462587Sitojun *
58562587Sitojun * nfs_namei() clears out garbage fields that namei() might leave garbage.
58662587Sitojun * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
58753541Sshin * error occurs but the parent was not requested.
58853541Sshin *
58962587Sitojun * dirp may be set whether an error is returned or not, and must be
590148385Sume * released by the caller.
59162587Sitojun */
59262587Sitojunint
59362587Sitojunnfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
59462587Sitojun    struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
59553541Sshin    caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag)
596148385Sume{
597148385Sume	int i, rem;
598150202Ssuz	struct mbuf *md;
59953541Sshin	char *fromcp, *tocp, *cp;
60053541Sshin	struct iovec aiov;
60178064Sume	struct uio auio;
60253541Sshin	struct vnode *dp;
603165118Sbz	int error, rdonly, linklen;
60478064Sume	struct componentname *cnp = &ndp->ni_cnd;
60553541Sshin
60653541Sshin	*retdirp = NULL;
60753541Sshin	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
60878064Sume
60978064Sume	/*
61078064Sume	 * Copy the name from the mbuf list to ndp->ni_pnbuf
61153541Sshin	 * and set the various ndp fields appropriately.
61253541Sshin	 */
61353541Sshin	fromcp = *dposp;
61453541Sshin	tocp = cnp->cn_pnbuf;
61553541Sshin	md = *mdp;
61678064Sume	rem = mtod(md, caddr_t) + md->m_len - fromcp;
61778064Sume	for (i = 0; i < len; i++) {
61878064Sume		while (rem == 0) {
61962587Sitojun			md = md->m_next;
62053541Sshin			if (md == NULL) {
62153541Sshin				error = EBADRPC;
62253541Sshin				goto out;
62353541Sshin			}
62453541Sshin			fromcp = mtod(md, caddr_t);
62553541Sshin			rem = md->m_len;
62653541Sshin		}
62753541Sshin		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
62853541Sshin			error = EACCES;
62953541Sshin			goto out;
63053541Sshin		}
63153541Sshin		*tocp++ = *fromcp++;
63253541Sshin		rem--;
63353541Sshin	}
63453541Sshin	*tocp = '\0';
63553541Sshin	*mdp = md;
63653541Sshin	*dposp = fromcp;
63753541Sshin	len = nfsm_rndup(len)-len;
63853541Sshin	if (len > 0) {
63953541Sshin		if (rem >= len)
64053541Sshin			*dposp += len;
64162587Sitojun		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
64253541Sshin			goto out;
64353541Sshin	}
64495023Ssuz
64553541Sshin	/*
64653541Sshin	 * Extract and set starting directory.
64753541Sshin	 */
648165118Sbz	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
64962587Sitojun	    nam, &rdonly, pubflag);
65053541Sshin	if (error)
65153541Sshin		goto out;
65253541Sshin	if (dp->v_type != VDIR) {
653120941Sume		vrele(dp);
654165118Sbz		error = ENOTDIR;
655120941Sume		goto out;
65678064Sume	}
65753541Sshin
65853541Sshin	if (rdonly)
65953541Sshin		cnp->cn_flags |= RDONLY;
660120941Sume
661120941Sume	/*
66253541Sshin	 * Set return directory.  Reference to dp is implicitly transfered
66353541Sshin	 * to the returned pointer
66453541Sshin	 */
66553541Sshin	*retdirp = dp;
66653541Sshin
66762587Sitojun	if (pubflag) {
66853541Sshin		/*
66953541Sshin		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
67053541Sshin		 * and the 'native path' indicator.
67153541Sshin		 */
67253541Sshin		cp = uma_zalloc(namei_zone, M_WAITOK);
67353541Sshin		fromcp = cnp->cn_pnbuf;
674151465Ssuz		tocp = cp;
67562587Sitojun		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
67653541Sshin			switch ((unsigned char)*fromcp) {
67753541Sshin			case WEBNFS_NATIVE_CHAR:
67853541Sshin				/*
67953541Sshin				 * 'Native' path for us is the same
68053541Sshin				 * as a path according to the NFS spec,
68153541Sshin				 * just skip the escape char.
68253541Sshin				 */
68353541Sshin				fromcp++;
68462587Sitojun				break;
685151539Ssuz			/*
686151539Ssuz			 * More may be added in the future, range 0x80-0xff
687151539Ssuz			 */
688120941Sume			default:
68978064Sume				error = EIO;
69053541Sshin				uma_zfree(namei_zone, cp);
691151539Ssuz				goto out;
69278064Sume			}
69378064Sume		}
69478064Sume		/*
69578064Sume		 * Translate the '%' escapes, URL-style.
69678064Sume		 */
69778064Sume		while (*fromcp != '\0') {
69878064Sume			if (*fromcp == WEBNFS_ESC_CHAR) {
69978064Sume				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
70078064Sume					fromcp++;
70153541Sshin					*tocp++ = HEXSTRTOI(fromcp);
70253541Sshin					fromcp += 2;
70353541Sshin					continue;
70453541Sshin				} else {
70553541Sshin					error = ENOENT;
70653541Sshin					uma_zfree(namei_zone, cp);
707151465Ssuz					goto out;
70853541Sshin				}
70953541Sshin			} else
71053541Sshin				*tocp++ = *fromcp++;
71153541Sshin		}
71253541Sshin		*tocp = '\0';
71353541Sshin		uma_zfree(namei_zone, cnp->cn_pnbuf);
71453541Sshin		cnp->cn_pnbuf = cp;
71553541Sshin	}
71653541Sshin
71753541Sshin	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
71853541Sshin	ndp->ni_segflg = UIO_SYSSPACE;
71953541Sshin
72053541Sshin	if (pubflag) {
72153541Sshin		ndp->ni_rootdir = rootvnode;
72253541Sshin		ndp->ni_loopcnt = 0;
72353541Sshin		if (cnp->cn_pnbuf[0] == '/')
72453541Sshin			dp = rootvnode;
72553541Sshin	} else {
72653541Sshin		cnp->cn_flags |= NOCROSSMOUNT;
72753541Sshin	}
72853541Sshin
72953541Sshin	/*
73053541Sshin	 * Initialize for scan, set ni_startdir and bump ref on dp again
73153541Sshin	 * becuase lookup() will dereference ni_startdir.
73253541Sshin	 */
73353541Sshin
73453541Sshin	cnp->cn_thread = td;
73553541Sshin	VREF(dp);
73653541Sshin	ndp->ni_startdir = dp;
73753541Sshin
738151539Ssuz	for (;;) {
73953541Sshin		cnp->cn_nameptr = cnp->cn_pnbuf;
74053541Sshin		/*
74153541Sshin		 * Call lookup() to do the real work.  If an error occurs,
74253541Sshin		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
74378064Sume		 * we do not have to dereference anything before returning.
74453541Sshin		 * In either case ni_startdir will be dereferenced and NULLed
745151539Ssuz		 * out.
74678064Sume		 */
74762587Sitojun		error = lookup(ndp);
74853541Sshin		if (error)
749151465Ssuz			break;
750151465Ssuz
75153541Sshin		/*
75253541Sshin		 * Check for encountering a symbolic link.  Trivial
75353541Sshin		 * termination occurs if no symlink encountered.
754151465Ssuz		 * Note: zfree is safe because error is 0, so we will
75553541Sshin		 * not zfree it again when we break.
75653541Sshin		 */
75753541Sshin		if ((cnp->cn_flags & ISSYMLINK) == 0) {
75853541Sshin			nfsrv_object_create(ndp->ni_vp);
75953541Sshin			if (cnp->cn_flags & (SAVENAME | SAVESTART))
76053541Sshin				cnp->cn_flags |= HASBUF;
76153541Sshin			else
76253541Sshin				uma_zfree(namei_zone, cnp->cn_pnbuf);
76353541Sshin			break;
76453541Sshin		}
76553541Sshin
76662587Sitojun		/*
767151539Ssuz		 * Validate symlink
768151539Ssuz		 */
769151539Ssuz		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
77053541Sshin			VOP_UNLOCK(ndp->ni_dvp, 0, td);
77153541Sshin		if (!pubflag) {
772151465Ssuz			error = EINVAL;
77353541Sshin			goto badlink2;
774151539Ssuz		}
775151539Ssuz
77678064Sume		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
77753541Sshin			error = ELOOP;
77853541Sshin			goto badlink2;
77953541Sshin		}
78053541Sshin		if (ndp->ni_pathlen > 1)
78153541Sshin			cp = uma_zalloc(namei_zone, M_WAITOK);
78253541Sshin		else
78353541Sshin			cp = cnp->cn_pnbuf;
78453541Sshin		aiov.iov_base = cp;
78553541Sshin		aiov.iov_len = MAXPATHLEN;
78653541Sshin		auio.uio_iov = &aiov;
78753541Sshin		auio.uio_iovcnt = 1;
78853541Sshin		auio.uio_offset = 0;
78953541Sshin		auio.uio_rw = UIO_READ;
79053541Sshin		auio.uio_segflg = UIO_SYSSPACE;
79195023Ssuz		auio.uio_td = NULL;
79295023Ssuz		auio.uio_resid = MAXPATHLEN;
79395023Ssuz		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
79495023Ssuz		if (error) {
79595023Ssuz		badlink1:
796120941Sume			if (ndp->ni_pathlen > 1)
79795023Ssuz				uma_zfree(namei_zone, cp);
79853541Sshin		badlink2:
799128422Sluigi			vrele(ndp->ni_dvp);
80053541Sshin			vput(ndp->ni_vp);
80153541Sshin			break;
802151539Ssuz		}
80353541Sshin		linklen = MAXPATHLEN - auio.uio_resid;
80453541Sshin		if (linklen == 0) {
80553541Sshin			error = ENOENT;
80653541Sshin			goto badlink1;
80753541Sshin		}
80853541Sshin		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
80953541Sshin			error = ENAMETOOLONG;
810128422Sluigi			goto badlink1;
81153541Sshin		}
81253541Sshin
81353541Sshin		/*
81453541Sshin		 * Adjust or replace path
81553541Sshin		 */
81653541Sshin		if (ndp->ni_pathlen > 1) {
81753541Sshin			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
81853541Sshin			uma_zfree(namei_zone, cnp->cn_pnbuf);
819151539Ssuz			cnp->cn_pnbuf = cp;
820151539Ssuz		} else
821151539Ssuz			cnp->cn_pnbuf[linklen] = '\0';
822151539Ssuz		ndp->ni_pathlen += linklen;
823151539Ssuz
824151539Ssuz		/*
825151539Ssuz		 * Cleanup refs for next loop and check if root directory
826151539Ssuz		 * should replace current directory.  Normally ni_dvp
827151539Ssuz		 * becomes the new base directory and is cleaned up when
828151539Ssuz		 * we loop.  Explicitly null pointers after invalidation
829151539Ssuz		 * to clarify operation.
830151539Ssuz		 */
831151539Ssuz		vput(ndp->ni_vp);
832151539Ssuz		ndp->ni_vp = NULL;
833151539Ssuz
834151539Ssuz		if (cnp->cn_pnbuf[0] == '/') {
835151539Ssuz			vrele(ndp->ni_dvp);
836151539Ssuz			ndp->ni_dvp = ndp->ni_rootdir;
837151539Ssuz			VREF(ndp->ni_dvp);
838120941Sume		}
83953541Sshin		ndp->ni_startdir = ndp->ni_dvp;
84062587Sitojun		ndp->ni_dvp = NULL;
84162587Sitojun	}
84262587Sitojun
84378064Sume	/*
84478064Sume	 * nfs_namei() guarentees that fields will not contain garbage
84578064Sume	 * whether an error occurs or not.  This allows the caller to track
84678064Sume	 * cleanup state trivially.
84778064Sume	 */
84853541Sshinout:
84953541Sshin	if (error) {
85053541Sshin		uma_zfree(namei_zone, cnp->cn_pnbuf);
85153541Sshin		ndp->ni_vp = NULL;
85253541Sshin		ndp->ni_dvp = NULL;
85353541Sshin		ndp->ni_startdir = NULL;
85453541Sshin		cnp->cn_flags &= ~HASBUF;
85562587Sitojun	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
85662587Sitojun		ndp->ni_dvp = NULL;
85762587Sitojun	}
85853541Sshin	return (error);
85953541Sshin}
860148385Sume
86153541Sshin/*
862148385Sume * A fiddled version of m_adj() that ensures null fill to a long
86353541Sshin * boundary and only trims off the back end
86462587Sitojun */
86562587Sitojunvoid
86653541Sshinnfsm_adj(struct mbuf *mp, int len, int nul)
86753541Sshin{
86853541Sshin	struct mbuf *m;
86953541Sshin	int count, i;
87053541Sshin	char *cp;
871148385Sume
872148385Sume	/*
873148385Sume	 * Trim from tail.  Scan the mbuf chain,
87492733Speter	 * calculating its length and finding the last mbuf.
875148385Sume	 * If the adjustment only affects this mbuf, then just
87662587Sitojun	 * adjust and return.  Otherwise, rescan and truncate
877148385Sume	 * after the remaining size.
878148385Sume	 */
879148385Sume	count = 0;
880148385Sume	m = mp;
88162587Sitojun	for (;;) {
88262587Sitojun		count += m->m_len;
88362587Sitojun		if (m->m_next == NULL)
88462587Sitojun			break;
88562587Sitojun		m = m->m_next;
88662587Sitojun	}
88762587Sitojun	if (m->m_len > len) {
88862587Sitojun		m->m_len -= len;
88953541Sshin		if (nul > 0) {
89062587Sitojun			cp = mtod(m, caddr_t)+m->m_len-nul;
89153541Sshin			for (i = 0; i < nul; i++)
892111119Simp				*cp++ = '\0';
89362587Sitojun		}
894111119Simp		return;
89562587Sitojun	}
89662587Sitojun	count -= len;
89762587Sitojun	if (count < 0)
89862587Sitojun		count = 0;
89962587Sitojun	/*
90062587Sitojun	 * Correct length for chain is "count".
90162587Sitojun	 * Find the mbuf with last data, adjust its length,
90278064Sume	 * and toss data from remaining mbufs on chain.
90362587Sitojun	 */
904148385Sume	for (m = mp; m; m = m->m_next) {
90553541Sshin		if (m->m_len >= count) {
90653541Sshin			m->m_len = count;
90753541Sshin			if (nul > 0) {
90853541Sshin				cp = mtod(m, caddr_t)+m->m_len-nul;
90953541Sshin				for (i = 0; i < nul; i++)
91053541Sshin					*cp++ = '\0';
91153541Sshin			}
91253541Sshin			break;
91395023Ssuz		}
91453541Sshin		count -= m->m_len;
91553541Sshin	}
91653541Sshin	for (m = m->m_next;m;m = m->m_next)
91753541Sshin		m->m_len = 0;
91862587Sitojun}
91962587Sitojun
92053541Sshin/*
92153541Sshin * Make these functions instead of macros, so that the kernel text size
922148385Sume * doesn't get too big...
92353541Sshin */
924153227Sumevoid
925153227Sumenfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
926153227Sume    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
927153227Sume    struct mbuf **mbp, char **bposp)
928153227Sume{
929148385Sume	struct mbuf *mb = *mbp;
930148385Sume	char *bpos = *bposp;
931148385Sume	u_int32_t *tl;
93253541Sshin
933148385Sume	if (before_ret) {
934148385Sume		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
935148385Sume		*tl = nfsrv_nfs_false;
936148385Sume	} else {
937148385Sume		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
938148385Sume		*tl++ = nfsrv_nfs_true;
93953541Sshin		txdr_hyper(before_vap->va_size, tl);
94053541Sshin		tl += 2;
94153541Sshin		txdr_nfsv3time(&(before_vap->va_mtime), tl);
94253541Sshin		tl += 2;
943148385Sume		txdr_nfsv3time(&(before_vap->va_ctime), tl);
944148385Sume	}
945148385Sume	*bposp = bpos;
946165118Sbz	*mbp = mb;
947148385Sume	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
948148385Sume}
949165118Sbz
950148385Sumevoid
95153541Sshinnfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
952148385Sume    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
95353541Sshin{
95453541Sshin	struct mbuf *mb = *mbp;
95553541Sshin	char *bpos = *bposp;
95653541Sshin	u_int32_t *tl;
957121315Sume	struct nfs_fattr *fp;
95853541Sshin
95953541Sshin	if (after_ret) {
96053541Sshin		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
96153541Sshin		*tl = nfsrv_nfs_false;
96253541Sshin	} else {
96353541Sshin		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
96453541Sshin		*tl++ = nfsrv_nfs_true;
96562587Sitojun		fp = (struct nfs_fattr *)tl;
96662587Sitojun		nfsm_srvfattr(nfsd, after_vap, fp);
96762587Sitojun	}
96862587Sitojun	*mbp = mb;
96962587Sitojun	*bposp = bpos;
97062587Sitojun}
971142215Sglebius
972142215Sglebiusvoid
973142215Sglebiusnfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
974142215Sglebius    struct nfs_fattr *fp)
975142215Sglebius{
976142215Sglebius
977142215Sglebius	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
97862587Sitojun	fp->fa_uid = txdr_unsigned(vap->va_uid);
979142215Sglebius	fp->fa_gid = txdr_unsigned(vap->va_gid);
980142215Sglebius	if (nfsd->nd_flag & ND_NFSV3) {
98162587Sitojun		fp->fa_type = vtonfsv3_type(vap->va_type);
98262587Sitojun		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
98362587Sitojun		txdr_hyper(vap->va_size, &fp->fa3_size);
98462587Sitojun		txdr_hyper(vap->va_bytes, &fp->fa3_used);
98562587Sitojun		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
98662587Sitojun		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
98762587Sitojun		fp->fa3_fsid.nfsuquad[0] = 0;
98853541Sshin		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
98953541Sshin		fp->fa3_fileid.nfsuquad[0] = 0;
990120941Sume		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
99153541Sshin		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
99253541Sshin		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
99353541Sshin		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
99453541Sshin	} else {
99553541Sshin		fp->fa_type = vtonfsv2_type(vap->va_type);
99653541Sshin		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
99753541Sshin		fp->fa2_size = txdr_unsigned(vap->va_size);
99853541Sshin		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
99953541Sshin		if (vap->va_type == VFIFO)
100053541Sshin			fp->fa2_rdev = 0xffffffff;
100153541Sshin		else
100253541Sshin			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
100353541Sshin		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
100453541Sshin		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
100553541Sshin		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
100653541Sshin		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
100753541Sshin		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1008120941Sume		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
100953541Sshin	}
1010148385Sume}
1011148385Sume
1012148385Sume/*
1013148385Sume * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1014148385Sume * 	- look up fsid in mount list (if not found ret error)
1015148385Sume *	- get vp and export rights by calling VFS_FHTOVP()
1016148385Sume *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
101753541Sshin *	- if not lockflag unlock it with VOP_UNLOCK()
1018148385Sume */
1019148385Sumeint
1020148385Sumenfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1021148385Sume    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1022148385Sume    int *rdonlyp, int pubflag)
1023148385Sume{
1024148385Sume	struct thread *td = curthread; /* XXX */
1025148385Sume	struct mount *mp;
102653541Sshin	int i;
102753541Sshin	struct ucred *credanon;
102853541Sshin	int error, exflags;
102953541Sshin#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
103053541Sshin	struct sockaddr_int *saddr;
103153541Sshin#endif
103253541Sshin
103353541Sshin	*vpp = NULL;
103453541Sshin
103553541Sshin	if (nfs_ispublicfh(fhp)) {
103678064Sume		if (!pubflag || !nfs_pub.np_valid)
103778468Ssumikawa			return (ESTALE);
103878468Ssumikawa		fhp = &nfs_pub.np_handle;
103978468Ssumikawa	}
104078064Sume
104178064Sume	mp = vfs_getvfs(&fhp->fh_fsid);
104278064Sume	if (!mp)
1043142215Sglebius		return (ESTALE);
1044142215Sglebius	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1045142215Sglebius	if (error)
1046149829Sthompsa		return (error);
1047120049Smdodd	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1048147306Sbrooks	if (error)
104953541Sshin		return (error);
105053541Sshin#ifdef MNT_EXNORESPORT
105153541Sshin	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
105253541Sshin		saddr = (struct sockaddr_in *)nam;
105353541Sshin		if ((saddr->sin_family == AF_INET ||
105460938Sjake		     saddr->sin_family == AF_INET6) &&
105553541Sshin	/* same code for INET and INET6: sin*_port at same offet */
105660938Sjake		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
105753541Sshin			vput(*vpp);
105853541Sshin			*vpp = NULL;
105962587Sitojun			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
106053541Sshin		}
106153541Sshin	}
106253541Sshin#endif
106378064Sume	/*
106453541Sshin	 * Check/setup credentials.
106553541Sshin	 */
106653541Sshin	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
106778064Sume		cred->cr_uid = credanon->cr_uid;
106853541Sshin		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
106953541Sshin			cred->cr_groups[i] = credanon->cr_groups[i];
107053541Sshin		cred->cr_ngroups = i;
107153541Sshin	}
107253541Sshin	if (exflags & MNT_EXRDONLY)
107353541Sshin		*rdonlyp = 1;
107453541Sshin	else
107562587Sitojun		*rdonlyp = 0;
107653541Sshin
107753541Sshin	nfsrv_object_create(*vpp);
107853541Sshin
107953541Sshin	if (!lockflag)
108053541Sshin		VOP_UNLOCK(*vpp, 0, td);
108153541Sshin	return (0);
108278064Sume}
108378064Sume
108478064Sume
108578064Sume/*
108678064Sume * WebNFS: check if a filehandle is a public filehandle. For v3, this
108778064Sume * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
108878064Sume * transformed this to all zeroes in both cases, so check for it.
108978064Sume */
109078064Sumeint
109178064Sumenfs_ispublicfh(fhandle_t *fhp)
109278064Sume{
109378064Sume	char *cp = (char *)fhp;
109478064Sume	int i;
109578064Sume
109678064Sume	for (i = 0; i < NFSX_V3FH; i++)
109778064Sume		if (*cp++ != 0)
109878064Sume			return (FALSE);
109978064Sume	return (TRUE);
110053541Sshin}
1101148987Sume
110253541Sshin/*
110353541Sshin * This function compares two net addresses by family and returns TRUE
1104151539Ssuz * if they are the same host.
110553541Sshin * If there is any doubt, return FALSE.
1106151539Ssuz * The AF_INET family is handled as a special case so that address mbufs
110753541Sshin * don't need to be saved to store "struct in_addr", which is only 4 bytes.
110853541Sshin */
110953541Sshinint
1110165118Sbznetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
111153541Sshin{
111253541Sshin	struct sockaddr_in *inetaddr;
111353541Sshin
111453541Sshin	switch (family) {
111553541Sshin	case AF_INET:
111653541Sshin		inetaddr = (struct sockaddr_in *)nam;
111753541Sshin		if (inetaddr->sin_family == AF_INET &&
111853541Sshin		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
111953541Sshin			return (1);
112053541Sshin		break;
112153541Sshin#ifdef INET6
112253541Sshin	case AF_INET6:
112353541Sshin	{
112462587Sitojun		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
112562587Sitojun
112653541Sshin		inet6addr1 = (struct sockaddr_in6 *)nam;
1127165118Sbz		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
112853541Sshin	/* XXX - should test sin6_scope_id ? */
112953541Sshin		if (inet6addr1->sin6_family == AF_INET6 &&
113053541Sshin		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
113153541Sshin				       &inet6addr2->sin6_addr))
113253541Sshin			return (1);
113353541Sshin		break;
113453541Sshin	}
113553541Sshin#endif
113653541Sshin	default:
113753541Sshin		break;
113853541Sshin	};
1139151465Ssuz	return (0);
114053541Sshin}
1141120941Sume
114253541Sshin/*
1143120941Sume * Map errnos to NFS error numbers. For Version 3 also filter out error
114453541Sshin * numbers not specified for the associated procedure.
114553541Sshin */
114653541Sshinint
114753541Sshinnfsrv_errmap(struct nfsrv_descript *nd, int err)
114853541Sshin{
114953541Sshin	short *defaulterrp, *errp;
115053541Sshin	int e;
115162587Sitojun
115253541Sshin	if (nd->nd_flag & ND_NFSV3) {
1153165118Sbz	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
115453541Sshin		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
115553541Sshin		while (*++errp) {
115653541Sshin			if (*errp == err)
115753541Sshin				return (err);
115878064Sume			else if (*errp > err)
115953541Sshin				break;
116053541Sshin		}
116178064Sume		return ((int)*defaulterrp);
1162165118Sbz	    } else
116353541Sshin		return (err & 0xffff);
116453541Sshin	}
116553541Sshin	e = 0;
116653541Sshin	if (err <= ELAST)
116753541Sshin		e = nfsrv_v2errmap[err - 1];
116853541Sshin	if (e != 0)
116953541Sshin		return (e);
117053541Sshin	return (NFSERR_IO);
117195023Ssuz}
117253541Sshin
117353541Sshinint
117462587Sitojunnfsrv_object_create(struct vnode *vp)
1175151539Ssuz{
117662587Sitojun
1177121161Sume	if (vp == NULL || vp->v_type != VREG)
1178151539Ssuz		return (1);
117953541Sshin	return (vfs_object_create(vp, curthread, curthread->td_ucred));
1180151539Ssuz}
118153541Sshin
118253541Sshin/*
118353541Sshin * Sort the group list in increasing numerical order.
118478064Sume * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
118578064Sume *  that used to be here.)
118678064Sume */
118778064Sumevoid
118878064Sumenfsrvw_sort(gid_t *list, int num)
118978064Sume{
119078064Sume	int i, j;
119178064Sume	gid_t v;
119278064Sume
119378064Sume	/* Insertion sort. */
119478064Sume	for (i = 1; i < num; i++) {
119578064Sume		v = list[i];
119678064Sume		/* find correct slot for value v, moving others up */
119778064Sume		for (j = i; --j >= 0 && v < list[j];)
119878064Sume			list[j + 1] = list[j];
119978064Sume		list[j + 1] = v;
120078064Sume	}
120178064Sume}
120278064Sume
120378064Sume/*
120478064Sume * copy credentials making sure that the result can be compared with bcmp().
120578064Sume */
120678064Sumevoid
120778064Sumenfsrv_setcred(struct ucred *incred, struct ucred *outcred)
120878064Sume{
120953541Sshin	int i;
121053541Sshin
121153541Sshin	bzero((caddr_t)outcred, sizeof (struct ucred));
121253541Sshin	outcred->cr_ref = 1;
121353541Sshin	outcred->cr_uid = incred->cr_uid;
121453541Sshin	outcred->cr_ngroups = incred->cr_ngroups;
121553541Sshin	for (i = 0; i < incred->cr_ngroups; i++)
1216165118Sbz		outcred->cr_groups[i] = incred->cr_groups[i];
121753541Sshin	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
121895023Ssuz}
121953541Sshin
122053541Sshin/*
122153541Sshin * Helper functions for macros.
122262587Sitojun */
122353541Sshin
122453541Sshinvoid
122553541Sshinnfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
122653541Sshin{
122762587Sitojun	u_int32_t *tl;
122853541Sshin
122953541Sshin	if (v3) {
123053541Sshin		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
123162587Sitojun		*tl++ = txdr_unsigned(NFSX_V3FH);
123253541Sshin		bcopy(f, tl, NFSX_V3FH);
1233165118Sbz	} else {
123453541Sshin		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
123553541Sshin		bcopy(f, tl, NFSX_V2FH);
123653541Sshin	}
123753541Sshin}
123862587Sitojun
123953541Sshinvoid
1240165118Sbznfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
124153541Sshin{
124253541Sshin	u_int32_t *tl;
124353541Sshin
124453541Sshin	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
124562587Sitojun	*tl++ = nfsrv_nfs_true;
124662587Sitojun	*tl++ = txdr_unsigned(NFSX_V3FH);
124778064Sume	bcopy(f, tl, NFSX_V3FH);
1248120941Sume}
124962587Sitojun
125062587Sitojunint
125162587Sitojunnfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
125262587Sitojun{
125362587Sitojun	u_int32_t *tl;
125462587Sitojun
125562587Sitojun	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
125662587Sitojun	if (tl == NULL)
125753541Sshin		return EBADRPC;
125853541Sshin	*s = fxdr_unsigned(int32_t, *tl);
125953541Sshin	if (*s > m || *s <= 0)
126053541Sshin		return EBADRPC;
126153541Sshin	return 0;
126262587Sitojun}
1263120941Sume
1264151539Ssuzint
126553541Sshinnfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos)
126653541Sshin{
126753541Sshin	u_int32_t *tl;
126853541Sshin
126953541Sshin	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
127053541Sshin	if (tl == NULL)
127153541Sshin		return EBADRPC;
127253541Sshin	*s = fxdr_unsigned(int32_t, *tl);
127353541Sshin	if (*s > NFS_MAXNAMLEN)
127453541Sshin		return NFSERR_NAMETOL;
127553541Sshin	if (*s <= 0)
127653541Sshin		return EBADRPC;
127753541Sshin	return 0;
127853541Sshin}
127953541Sshin
128053541Sshinvoid
128153541Sshinnfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
128253541Sshin    char **bp, char **be, caddr_t bpos)
128353541Sshin{
128453541Sshin	struct mbuf *nmp;
128553541Sshin
128653541Sshin	if (*bp >= *be) {
128753541Sshin		if (*mp == mb)
128853541Sshin			(*mp)->m_len += *bp - bpos;
128953541Sshin		MGET(nmp, M_TRYWAIT, MT_DATA);
129053541Sshin		MCLGET(nmp, M_TRYWAIT);
129153541Sshin		nmp->m_len = NFSMSIZ(nmp);
129253541Sshin		(*mp)->m_next = nmp;
129353541Sshin		*mp = nmp;
1294148987Sume		*bp = mtod(*mp, caddr_t);
129553541Sshin		*be = *bp + (*mp)->m_len;
129653541Sshin	}
129753541Sshin	*tl = (u_int32_t *)*bp;
129878064Sume}
129962587Sitojun
130062587Sitojunint
1301165118Sbznfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
130253541Sshin    caddr_t *dpos)
130353541Sshin{
130453541Sshin	u_int32_t *tl;
130553541Sshin	int fhlen;
130662587Sitojun
130753541Sshin	if (nfsd->nd_flag & ND_NFSV3) {
130853541Sshin		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
130953541Sshin		if (tl == NULL)
131053541Sshin			return EBADRPC;
131153541Sshin		fhlen = fxdr_unsigned(int, *tl);
131253541Sshin		if (fhlen != 0 && fhlen != NFSX_V3FH)
131353541Sshin			return EBADRPC;
131453541Sshin	} else {
131553541Sshin		fhlen = NFSX_V2FH;
131653541Sshin	}
131753541Sshin	if (fhlen != 0) {
131853541Sshin		tl = nfsm_dissect_xx(fhlen, md, dpos);
1319151477Ssuz		if (tl == NULL)
132053541Sshin			return EBADRPC;
1321165118Sbz		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
132253541Sshin	} else {
132353541Sshin		bzero((caddr_t)(f), NFSX_V3FH);
132453541Sshin	}
132562587Sitojun	return 0;
132653541Sshin}
132753541Sshin
132853541Sshinint
132978064Sumenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
133078064Sume{
1331165118Sbz	u_int32_t *tl;
133278064Sume
133353541Sshin	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
133453541Sshin	if (tl == NULL)
133553541Sshin		return EBADRPC;
133653541Sshin	if (*tl == nfsrv_nfs_true) {
1337148987Sume		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
133878064Sume		if (tl == NULL)
133953541Sshin			return EBADRPC;
1340151477Ssuz		(a)->va_mode = nfstov_mode(*tl);
134162587Sitojun	}
1342165118Sbz	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
134362587Sitojun	if (tl == NULL)
1344151477Ssuz		return EBADRPC;
134553541Sshin	if (*tl == nfsrv_nfs_true) {
1346151477Ssuz		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1347151477Ssuz		if (tl == NULL)
1348151477Ssuz			return EBADRPC;
1349151477Ssuz		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
1350151477Ssuz	}
1351151477Ssuz	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1352151477Ssuz	if (tl == NULL)
1353151477Ssuz		return EBADRPC;
1354151477Ssuz	if (*tl == nfsrv_nfs_true) {
1355151477Ssuz		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1356151477Ssuz		if (tl == NULL)
1357151477Ssuz			return EBADRPC;
1358151477Ssuz		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
1359151477Ssuz	}
1360151477Ssuz	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1361151477Ssuz	if (tl == NULL)
1362151477Ssuz		return EBADRPC;
1363151477Ssuz	if (*tl == nfsrv_nfs_true) {
1364151477Ssuz		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1365151477Ssuz		if (tl == NULL)
1366151477Ssuz			return EBADRPC;
1367151477Ssuz		(a)->va_size = fxdr_hyper(tl);
1368151477Ssuz	}
1369151477Ssuz	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1370151477Ssuz	if (tl == NULL)
1371151477Ssuz		return EBADRPC;
1372151477Ssuz	switch (fxdr_unsigned(int, *tl)) {
1373151477Ssuz	case NFSV3SATTRTIME_TOCLIENT:
1374151477Ssuz		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1375151477Ssuz		if (tl == NULL)
1376151477Ssuz			return EBADRPC;
1377151477Ssuz		fxdr_nfsv3time(tl, &(a)->va_atime);
1378151477Ssuz		break;
1379151477Ssuz	case NFSV3SATTRTIME_TOSERVER:
138053541Sshin		getnanotime(&(a)->va_atime);
138153541Sshin		break;
138253541Sshin	}
138362587Sitojun	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
138453541Sshin	if (tl == NULL)
138553541Sshin		return EBADRPC;
138662587Sitojun	switch (fxdr_unsigned(int, *tl)) {
138762587Sitojun	case NFSV3SATTRTIME_TOCLIENT:
138862587Sitojun		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
138962587Sitojun		if (tl == NULL)
139062587Sitojun			return EBADRPC;
139162587Sitojun		fxdr_nfsv3time(tl, &(a)->va_mtime);
139262587Sitojun		break;
139362587Sitojun	case NFSV3SATTRTIME_TOSERVER:
139462587Sitojun		getnanotime(&(a)->va_mtime);
139562587Sitojun		break;
139662587Sitojun	}
139762587Sitojun	return 0;
1398148887Srwatson}
139962587Sitojun