nfs_srvsubs.c revision 106264
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Rick Macklem at The University of Guelph.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 3. All advertising materials mentioning features or use of this software
171541Srgrimes *    must display the following acknowledgement:
181541Srgrimes *	This product includes software developed by the University of
191541Srgrimes *	California, Berkeley and its contributors.
201541Srgrimes * 4. Neither the name of the University nor the names of its contributors
211541Srgrimes *    may be used to endorse or promote products derived from this software
221541Srgrimes *    without specific prior written permission.
231541Srgrimes *
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341541Srgrimes * SUCH DAMAGE.
351541Srgrimes *
3636503Speter *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
3750477Speter * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 106264 2002-10-31 22:35:03Z jeff $
381541Srgrimes */
391541Srgrimes
4083651Speter#include <sys/cdefs.h>
4183651Speter__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 106264 2002-10-31 22:35:03Z jeff $");
4283651Speter
431541Srgrimes/*
441541Srgrimes * These functions support the macros and help fiddle mbuf chains for
451541Srgrimes * the nfs op functions. They do things like create the rpc header and
461541Srgrimes * copy data between mbuf chains and uio lists.
471541Srgrimes */
4883651Speter
49100134Salfred#include "opt_inet6.h"
50100134Salfred
511541Srgrimes#include <sys/param.h>
5248274Speter#include <sys/systm.h>
5348274Speter#include <sys/kernel.h>
5460041Sphk#include <sys/bio.h>
5531886Sbde#include <sys/buf.h>
561541Srgrimes#include <sys/proc.h>
571541Srgrimes#include <sys/mount.h>
581541Srgrimes#include <sys/vnode.h>
591541Srgrimes#include <sys/namei.h>
601541Srgrimes#include <sys/mbuf.h>
611541Srgrimes#include <sys/socket.h>
621541Srgrimes#include <sys/stat.h>
639336Sdfr#include <sys/malloc.h>
6483700Speter#include <sys/module.h>
652997Swollman#include <sys/sysent.h>
662997Swollman#include <sys/syscall.h>
6783651Speter#include <sys/sysproto.h>
681541Srgrimes
693305Sphk#include <vm/vm.h>
7012662Sdg#include <vm/vm_object.h>
7112662Sdg#include <vm/vm_extern.h>
7292783Sjeff#include <vm/uma.h>
733305Sphk
741541Srgrimes#include <nfs/rpcv2.h>
759336Sdfr#include <nfs/nfsproto.h>
7683651Speter#include <nfsserver/nfs.h>
771541Srgrimes#include <nfs/xdr_subs.h>
7883651Speter#include <nfsserver/nfsm_subs.h>
791541Srgrimes
801541Srgrimes#include <netinet/in.h>
811541Srgrimes
821541Srgrimes/*
831541Srgrimes * Data items converted to xdr at startup, since they are constant
841541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
851541Srgrimes */
8689094Smsmithu_int32_t nfsrv_nfs_xdrneg1;
8789094Smsmithu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
8889094Smsmith	nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
8989094Smsmith	nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
9089094Smsmithu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
911541Srgrimes
921541Srgrimes/* And other global data */
9383651Speterstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
9483651Speter				 NFNON, NFCHR, NFNON };
9583651Speter#define vtonfsv2_type(a)	txdr_unsigned(nfsv2_type[((int32_t)(a))])
9683651Speter#define vtonfsv3_mode(m)	txdr_unsigned((m) & ALLPERMS)
9712911Sphk
9889094Smsmithint nfsrv_ticks;
999336Sdfr
1009759Sbdestruct nfssvc_sockhead nfssvc_sockhead;
1019759Sbdeint nfssvc_sockhead_flag;
1029759Sbdestruct nfsd_head nfsd_head;
1039759Sbdeint nfsd_head_flag;
1049759Sbde
10538894Sbdestatic int nfs_prev_nfssvc_sy_narg;
10638894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call;
10738894Sbde
1089336Sdfr/*
1099336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
1109336Sdfr */
11189094Smsmithint nfsrv_nfsv3_procid[NFS_NPROCS] = {
1129336Sdfr	NFSPROC_NULL,
1139336Sdfr	NFSPROC_GETATTR,
1149336Sdfr	NFSPROC_SETATTR,
1159336Sdfr	NFSPROC_NOOP,
1169336Sdfr	NFSPROC_LOOKUP,
1179336Sdfr	NFSPROC_READLINK,
1189336Sdfr	NFSPROC_READ,
1199336Sdfr	NFSPROC_NOOP,
1209336Sdfr	NFSPROC_WRITE,
1219336Sdfr	NFSPROC_CREATE,
1229336Sdfr	NFSPROC_REMOVE,
1239336Sdfr	NFSPROC_RENAME,
1249336Sdfr	NFSPROC_LINK,
1259336Sdfr	NFSPROC_SYMLINK,
1269336Sdfr	NFSPROC_MKDIR,
1279336Sdfr	NFSPROC_RMDIR,
1289336Sdfr	NFSPROC_READDIR,
1299336Sdfr	NFSPROC_FSSTAT,
1309336Sdfr	NFSPROC_NOOP,
1319336Sdfr	NFSPROC_NOOP,
1329336Sdfr	NFSPROC_NOOP,
1339336Sdfr	NFSPROC_NOOP,
1349336Sdfr	NFSPROC_NOOP,
1359336Sdfr};
1369336Sdfr
1379336Sdfr/*
1389336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers
1399336Sdfr */
14083651Speterint nfsrvv2_procid[NFS_NPROCS] = {
1419336Sdfr	NFSV2PROC_NULL,
1429336Sdfr	NFSV2PROC_GETATTR,
1439336Sdfr	NFSV2PROC_SETATTR,
1449336Sdfr	NFSV2PROC_LOOKUP,
1459336Sdfr	NFSV2PROC_NOOP,
1469336Sdfr	NFSV2PROC_READLINK,
1479336Sdfr	NFSV2PROC_READ,
1489336Sdfr	NFSV2PROC_WRITE,
1499336Sdfr	NFSV2PROC_CREATE,
1509336Sdfr	NFSV2PROC_MKDIR,
1519336Sdfr	NFSV2PROC_SYMLINK,
1529336Sdfr	NFSV2PROC_CREATE,
1539336Sdfr	NFSV2PROC_REMOVE,
1549336Sdfr	NFSV2PROC_RMDIR,
1559336Sdfr	NFSV2PROC_RENAME,
1569336Sdfr	NFSV2PROC_LINK,
1579336Sdfr	NFSV2PROC_READDIR,
1589336Sdfr	NFSV2PROC_NOOP,
1599336Sdfr	NFSV2PROC_STATFS,
1609336Sdfr	NFSV2PROC_NOOP,
1619336Sdfr	NFSV2PROC_NOOP,
1629336Sdfr	NFSV2PROC_NOOP,
1639336Sdfr	NFSV2PROC_NOOP,
1649336Sdfr};
1659336Sdfr
1669336Sdfr/*
1679336Sdfr * Maps errno values to nfs error numbers.
168102236Sphk * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
169102236Sphk * specifically defined in RFC 1094.
1709336Sdfr */
1719336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = {
172102236Sphk  NFSERR_PERM,	NFSERR_NOENT,	0,		0,		0,
173102236Sphk  NFSERR_NXIO,	0,		0,		0,		0,
174102236Sphk  0,		0,		NFSERR_ACCES,	0,		0,
175102236Sphk  0,		NFSERR_EXIST,	0,		NFSERR_NODEV,	NFSERR_NOTDIR,
176102236Sphk  NFSERR_ISDIR,	0,		0,		0,		0,
177102236Sphk  0,		NFSERR_FBIG,	NFSERR_NOSPC,	0,		NFSERR_ROFS,
178102236Sphk  0,		0,		0,		0,		0,
179102236Sphk  0,		0,		0,		0,		0,
180102236Sphk  0,		0,		0,		0,		0,
181102236Sphk  0,		0,		0,		0,		0,
182102236Sphk  0,		0,		0,		0,		0,
183102236Sphk  0,		0,		0,		0,		0,
184102236Sphk  0,		0,		NFSERR_NAMETOL,	0,		0,
185102236Sphk  NFSERR_NOTEMPTY, 0,		0,		NFSERR_DQUOT,	NFSERR_STALE,
186102236Sphk  0
1879336Sdfr};
1889336Sdfr
1899336Sdfr/*
1909336Sdfr * Maps errno values to nfs error numbers.
1919336Sdfr * Although it is not obvious whether or not NFS clients really care if
1929336Sdfr * a returned error value is in the specified list for the procedure, the
1939336Sdfr * safest thing to do is filter them appropriately. For Version 2, the
1949336Sdfr * X/Open XNFS document is the only specification that defines error values
1959336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs),
1969336Sdfr * so I have decided to not do this for Version 2.
1979336Sdfr * The first entry is the default error return and the rest are the valid
1989336Sdfr * errors for that RPC in increasing numeric order.
1999336Sdfr */
2009336Sdfrstatic short nfsv3err_null[] = {
2019336Sdfr	0,
2029336Sdfr	0,
2039336Sdfr};
2049336Sdfr
2059336Sdfrstatic short nfsv3err_getattr[] = {
2069336Sdfr	NFSERR_IO,
2079336Sdfr	NFSERR_IO,
2089336Sdfr	NFSERR_STALE,
2099336Sdfr	NFSERR_BADHANDLE,
2109336Sdfr	NFSERR_SERVERFAULT,
2119336Sdfr	0,
2129336Sdfr};
2139336Sdfr
2149336Sdfrstatic short nfsv3err_setattr[] = {
2159336Sdfr	NFSERR_IO,
2169336Sdfr	NFSERR_PERM,
2179336Sdfr	NFSERR_IO,
2189336Sdfr	NFSERR_ACCES,
2199336Sdfr	NFSERR_INVAL,
2209336Sdfr	NFSERR_NOSPC,
2219336Sdfr	NFSERR_ROFS,
2229336Sdfr	NFSERR_DQUOT,
2239336Sdfr	NFSERR_STALE,
2249336Sdfr	NFSERR_BADHANDLE,
2259336Sdfr	NFSERR_NOT_SYNC,
2269336Sdfr	NFSERR_SERVERFAULT,
2279336Sdfr	0,
2289336Sdfr};
2299336Sdfr
2309336Sdfrstatic short nfsv3err_lookup[] = {
2319336Sdfr	NFSERR_IO,
2329336Sdfr	NFSERR_NOENT,
2339336Sdfr	NFSERR_IO,
2349336Sdfr	NFSERR_ACCES,
2359336Sdfr	NFSERR_NOTDIR,
2369336Sdfr	NFSERR_NAMETOL,
2379336Sdfr	NFSERR_STALE,
2389336Sdfr	NFSERR_BADHANDLE,
2399336Sdfr	NFSERR_SERVERFAULT,
2409336Sdfr	0,
2419336Sdfr};
2429336Sdfr
2439336Sdfrstatic short nfsv3err_access[] = {
2449336Sdfr	NFSERR_IO,
2459336Sdfr	NFSERR_IO,
2469336Sdfr	NFSERR_STALE,
2479336Sdfr	NFSERR_BADHANDLE,
2489336Sdfr	NFSERR_SERVERFAULT,
2499336Sdfr	0,
2509336Sdfr};
2519336Sdfr
2529336Sdfrstatic short nfsv3err_readlink[] = {
2539336Sdfr	NFSERR_IO,
2549336Sdfr	NFSERR_IO,
2559336Sdfr	NFSERR_ACCES,
2569336Sdfr	NFSERR_INVAL,
2579336Sdfr	NFSERR_STALE,
2589336Sdfr	NFSERR_BADHANDLE,
2599336Sdfr	NFSERR_NOTSUPP,
2609336Sdfr	NFSERR_SERVERFAULT,
2619336Sdfr	0,
2629336Sdfr};
2639336Sdfr
2649336Sdfrstatic short nfsv3err_read[] = {
2659336Sdfr	NFSERR_IO,
2669336Sdfr	NFSERR_IO,
2679336Sdfr	NFSERR_NXIO,
2689336Sdfr	NFSERR_ACCES,
2699336Sdfr	NFSERR_INVAL,
2709336Sdfr	NFSERR_STALE,
2719336Sdfr	NFSERR_BADHANDLE,
2729336Sdfr	NFSERR_SERVERFAULT,
2739336Sdfr	0,
2749336Sdfr};
2759336Sdfr
2769336Sdfrstatic short nfsv3err_write[] = {
2779336Sdfr	NFSERR_IO,
2789336Sdfr	NFSERR_IO,
2799336Sdfr	NFSERR_ACCES,
2809336Sdfr	NFSERR_INVAL,
2819336Sdfr	NFSERR_FBIG,
2829336Sdfr	NFSERR_NOSPC,
2839336Sdfr	NFSERR_ROFS,
2849336Sdfr	NFSERR_DQUOT,
2859336Sdfr	NFSERR_STALE,
2869336Sdfr	NFSERR_BADHANDLE,
2879336Sdfr	NFSERR_SERVERFAULT,
2889336Sdfr	0,
2899336Sdfr};
2909336Sdfr
2919336Sdfrstatic short nfsv3err_create[] = {
2929336Sdfr	NFSERR_IO,
2939336Sdfr	NFSERR_IO,
2949336Sdfr	NFSERR_ACCES,
2959336Sdfr	NFSERR_EXIST,
2969336Sdfr	NFSERR_NOTDIR,
2979336Sdfr	NFSERR_NOSPC,
2989336Sdfr	NFSERR_ROFS,
2999336Sdfr	NFSERR_NAMETOL,
3009336Sdfr	NFSERR_DQUOT,
3019336Sdfr	NFSERR_STALE,
3029336Sdfr	NFSERR_BADHANDLE,
3039336Sdfr	NFSERR_NOTSUPP,
3049336Sdfr	NFSERR_SERVERFAULT,
3059336Sdfr	0,
3069336Sdfr};
3079336Sdfr
3089336Sdfrstatic short nfsv3err_mkdir[] = {
3099336Sdfr	NFSERR_IO,
3109336Sdfr	NFSERR_IO,
3119336Sdfr	NFSERR_ACCES,
3129336Sdfr	NFSERR_EXIST,
3139336Sdfr	NFSERR_NOTDIR,
3149336Sdfr	NFSERR_NOSPC,
3159336Sdfr	NFSERR_ROFS,
3169336Sdfr	NFSERR_NAMETOL,
3179336Sdfr	NFSERR_DQUOT,
3189336Sdfr	NFSERR_STALE,
3199336Sdfr	NFSERR_BADHANDLE,
3209336Sdfr	NFSERR_NOTSUPP,
3219336Sdfr	NFSERR_SERVERFAULT,
3229336Sdfr	0,
3239336Sdfr};
3249336Sdfr
3259336Sdfrstatic short nfsv3err_symlink[] = {
3269336Sdfr	NFSERR_IO,
3279336Sdfr	NFSERR_IO,
3289336Sdfr	NFSERR_ACCES,
3299336Sdfr	NFSERR_EXIST,
3309336Sdfr	NFSERR_NOTDIR,
3319336Sdfr	NFSERR_NOSPC,
3329336Sdfr	NFSERR_ROFS,
3339336Sdfr	NFSERR_NAMETOL,
3349336Sdfr	NFSERR_DQUOT,
3359336Sdfr	NFSERR_STALE,
3369336Sdfr	NFSERR_BADHANDLE,
3379336Sdfr	NFSERR_NOTSUPP,
3389336Sdfr	NFSERR_SERVERFAULT,
3399336Sdfr	0,
3409336Sdfr};
3419336Sdfr
3429336Sdfrstatic short nfsv3err_mknod[] = {
3439336Sdfr	NFSERR_IO,
3449336Sdfr	NFSERR_IO,
3459336Sdfr	NFSERR_ACCES,
3469336Sdfr	NFSERR_EXIST,
3479336Sdfr	NFSERR_NOTDIR,
3489336Sdfr	NFSERR_NOSPC,
3499336Sdfr	NFSERR_ROFS,
3509336Sdfr	NFSERR_NAMETOL,
3519336Sdfr	NFSERR_DQUOT,
3529336Sdfr	NFSERR_STALE,
3539336Sdfr	NFSERR_BADHANDLE,
3549336Sdfr	NFSERR_NOTSUPP,
3559336Sdfr	NFSERR_SERVERFAULT,
3569336Sdfr	NFSERR_BADTYPE,
3579336Sdfr	0,
3589336Sdfr};
3599336Sdfr
3609336Sdfrstatic short nfsv3err_remove[] = {
3619336Sdfr	NFSERR_IO,
3629336Sdfr	NFSERR_NOENT,
3639336Sdfr	NFSERR_IO,
3649336Sdfr	NFSERR_ACCES,
3659336Sdfr	NFSERR_NOTDIR,
3669336Sdfr	NFSERR_ROFS,
3679336Sdfr	NFSERR_NAMETOL,
3689336Sdfr	NFSERR_STALE,
3699336Sdfr	NFSERR_BADHANDLE,
3709336Sdfr	NFSERR_SERVERFAULT,
3719336Sdfr	0,
3729336Sdfr};
3739336Sdfr
3749336Sdfrstatic short nfsv3err_rmdir[] = {
3759336Sdfr	NFSERR_IO,
3769336Sdfr	NFSERR_NOENT,
3779336Sdfr	NFSERR_IO,
3789336Sdfr	NFSERR_ACCES,
3799336Sdfr	NFSERR_EXIST,
3809336Sdfr	NFSERR_NOTDIR,
3819336Sdfr	NFSERR_INVAL,
3829336Sdfr	NFSERR_ROFS,
3839336Sdfr	NFSERR_NAMETOL,
3849336Sdfr	NFSERR_NOTEMPTY,
3859336Sdfr	NFSERR_STALE,
3869336Sdfr	NFSERR_BADHANDLE,
3879336Sdfr	NFSERR_NOTSUPP,
3889336Sdfr	NFSERR_SERVERFAULT,
3899336Sdfr	0,
3909336Sdfr};
3919336Sdfr
3929336Sdfrstatic short nfsv3err_rename[] = {
3939336Sdfr	NFSERR_IO,
3949336Sdfr	NFSERR_NOENT,
3959336Sdfr	NFSERR_IO,
3969336Sdfr	NFSERR_ACCES,
3979336Sdfr	NFSERR_EXIST,
3989336Sdfr	NFSERR_XDEV,
3999336Sdfr	NFSERR_NOTDIR,
4009336Sdfr	NFSERR_ISDIR,
4019336Sdfr	NFSERR_INVAL,
4029336Sdfr	NFSERR_NOSPC,
4039336Sdfr	NFSERR_ROFS,
4049336Sdfr	NFSERR_MLINK,
4059336Sdfr	NFSERR_NAMETOL,
4069336Sdfr	NFSERR_NOTEMPTY,
4079336Sdfr	NFSERR_DQUOT,
4089336Sdfr	NFSERR_STALE,
4099336Sdfr	NFSERR_BADHANDLE,
4109336Sdfr	NFSERR_NOTSUPP,
4119336Sdfr	NFSERR_SERVERFAULT,
4129336Sdfr	0,
4139336Sdfr};
4149336Sdfr
4159336Sdfrstatic short nfsv3err_link[] = {
4169336Sdfr	NFSERR_IO,
4179336Sdfr	NFSERR_IO,
4189336Sdfr	NFSERR_ACCES,
4199336Sdfr	NFSERR_EXIST,
4209336Sdfr	NFSERR_XDEV,
4219336Sdfr	NFSERR_NOTDIR,
4229336Sdfr	NFSERR_INVAL,
4239336Sdfr	NFSERR_NOSPC,
4249336Sdfr	NFSERR_ROFS,
4259336Sdfr	NFSERR_MLINK,
4269336Sdfr	NFSERR_NAMETOL,
4279336Sdfr	NFSERR_DQUOT,
4289336Sdfr	NFSERR_STALE,
4299336Sdfr	NFSERR_BADHANDLE,
4309336Sdfr	NFSERR_NOTSUPP,
4319336Sdfr	NFSERR_SERVERFAULT,
4329336Sdfr	0,
4339336Sdfr};
4349336Sdfr
4359336Sdfrstatic short nfsv3err_readdir[] = {
4369336Sdfr	NFSERR_IO,
4379336Sdfr	NFSERR_IO,
4389336Sdfr	NFSERR_ACCES,
4399336Sdfr	NFSERR_NOTDIR,
4409336Sdfr	NFSERR_STALE,
4419336Sdfr	NFSERR_BADHANDLE,
4429336Sdfr	NFSERR_BAD_COOKIE,
4439336Sdfr	NFSERR_TOOSMALL,
4449336Sdfr	NFSERR_SERVERFAULT,
4459336Sdfr	0,
4469336Sdfr};
4479336Sdfr
4489336Sdfrstatic short nfsv3err_readdirplus[] = {
4499336Sdfr	NFSERR_IO,
4509336Sdfr	NFSERR_IO,
4519336Sdfr	NFSERR_ACCES,
4529336Sdfr	NFSERR_NOTDIR,
4539336Sdfr	NFSERR_STALE,
4549336Sdfr	NFSERR_BADHANDLE,
4559336Sdfr	NFSERR_BAD_COOKIE,
4569336Sdfr	NFSERR_NOTSUPP,
4579336Sdfr	NFSERR_TOOSMALL,
4589336Sdfr	NFSERR_SERVERFAULT,
4599336Sdfr	0,
4609336Sdfr};
4619336Sdfr
4629336Sdfrstatic short nfsv3err_fsstat[] = {
4639336Sdfr	NFSERR_IO,
4649336Sdfr	NFSERR_IO,
4659336Sdfr	NFSERR_STALE,
4669336Sdfr	NFSERR_BADHANDLE,
4679336Sdfr	NFSERR_SERVERFAULT,
4689336Sdfr	0,
4699336Sdfr};
4709336Sdfr
4719336Sdfrstatic short nfsv3err_fsinfo[] = {
4729336Sdfr	NFSERR_STALE,
4739336Sdfr	NFSERR_STALE,
4749336Sdfr	NFSERR_BADHANDLE,
4759336Sdfr	NFSERR_SERVERFAULT,
4769336Sdfr	0,
4779336Sdfr};
4789336Sdfr
4799336Sdfrstatic short nfsv3err_pathconf[] = {
4809336Sdfr	NFSERR_STALE,
4819336Sdfr	NFSERR_STALE,
4829336Sdfr	NFSERR_BADHANDLE,
4839336Sdfr	NFSERR_SERVERFAULT,
4849336Sdfr	0,
4859336Sdfr};
4869336Sdfr
4879336Sdfrstatic short nfsv3err_commit[] = {
4889336Sdfr	NFSERR_IO,
4899336Sdfr	NFSERR_IO,
4909336Sdfr	NFSERR_STALE,
4919336Sdfr	NFSERR_BADHANDLE,
4929336Sdfr	NFSERR_SERVERFAULT,
4939336Sdfr	0,
4949336Sdfr};
4959336Sdfr
4969336Sdfrstatic short *nfsrv_v3errmap[] = {
4979336Sdfr	nfsv3err_null,
4989336Sdfr	nfsv3err_getattr,
4999336Sdfr	nfsv3err_setattr,
5009336Sdfr	nfsv3err_lookup,
5019336Sdfr	nfsv3err_access,
5029336Sdfr	nfsv3err_readlink,
5039336Sdfr	nfsv3err_read,
5049336Sdfr	nfsv3err_write,
5059336Sdfr	nfsv3err_create,
5069336Sdfr	nfsv3err_mkdir,
5079336Sdfr	nfsv3err_symlink,
5089336Sdfr	nfsv3err_mknod,
5099336Sdfr	nfsv3err_remove,
5109336Sdfr	nfsv3err_rmdir,
5119336Sdfr	nfsv3err_rename,
5129336Sdfr	nfsv3err_link,
5139336Sdfr	nfsv3err_readdir,
5149336Sdfr	nfsv3err_readdirplus,
5159336Sdfr	nfsv3err_fsstat,
5169336Sdfr	nfsv3err_fsinfo,
5179336Sdfr	nfsv3err_pathconf,
5189336Sdfr	nfsv3err_commit,
5199336Sdfr};
5209336Sdfr
5211541Srgrimes/*
5221541Srgrimes * Called once to initialize data structures...
5231541Srgrimes */
52483651Speterstatic int
52583700Speternfsrv_modevent(module_t mod, int type, void *data)
5261541Srgrimes{
5271541Srgrimes
52883700Speter	switch (type) {
52983700Speter	case MOD_LOAD:
53089094Smsmith		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
53189094Smsmith		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
53289094Smsmith		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
53389094Smsmith		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
53489094Smsmith		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
53589094Smsmith		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
53689094Smsmith		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
53789094Smsmith		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
53889094Smsmith		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
53989094Smsmith		nfsrv_nfs_true = txdr_unsigned(TRUE);
54089094Smsmith		nfsrv_nfs_false = txdr_unsigned(FALSE);
54189094Smsmith		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
54289094Smsmith		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
54389094Smsmith		if (nfsrv_ticks < 1)
54489094Smsmith			nfsrv_ticks = 1;
54583651Speter
54683700Speter		nfsrv_init(0);		/* Init server data structures */
54783700Speter		nfsrv_initcache();	/* Init the server request cache */
5481541Srgrimes
54983700Speter		nfsrv_timer(0);
5501541Srgrimes
55183700Speter		nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
55283700Speter		sysent[SYS_nfssvc].sy_narg = 2;
55383700Speter		nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
55483700Speter		sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
55583700Speter		break;
5562997Swollman
55783700Speter		case MOD_UNLOAD:
55883700Speter
55983700Speter		untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle);
56083700Speter		sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
56183700Speter		sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
56283700Speter		break;
56383700Speter	}
56483700Speter	return 0;
5651541Srgrimes}
56683700Speterstatic moduledata_t nfsserver_mod = {
56783700Speter	"nfsserver",
56883700Speter	nfsrv_modevent,
56983700Speter	NULL,
57083700Speter};
57183700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
5721541Srgrimes
57383700Speter/* So that loader and kldload(2) can find us, wherever we are.. */
57483700SpeterMODULE_VERSION(nfsserver, 1);
57538894Sbde
5761541Srgrimes/*
57727446Sdfr * Set up nameidata for a lookup() call and do it.
57827446Sdfr *
57927446Sdfr * If pubflag is set, this call is done for a lookup operation on the
58027446Sdfr * public filehandle. In that case we allow crossing mountpoints and
58127446Sdfr * absolute pathnames. However, the caller is expected to check that
58227446Sdfr * the lookup result is within the public fs, and deny access if
58327446Sdfr * it is not.
58448125Sjulian *
58548125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage.
58648125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
58748125Sjulian * error occurs but the parent was not requested.
58848125Sjulian *
58983651Speter * dirp may be set whether an error is returned or not, and must be
59048125Sjulian * released by the caller.
5911541Srgrimes */
5921549Srgrimesint
59383651Speternfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
59483651Speter    struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
59583651Speter    caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag)
5961541Srgrimes{
59783651Speter	int i, rem;
59883651Speter	struct mbuf *md;
59983651Speter	char *fromcp, *tocp, *cp;
60027446Sdfr	struct iovec aiov;
60127446Sdfr	struct uio auio;
6021541Srgrimes	struct vnode *dp;
60327446Sdfr	int error, rdonly, linklen;
6041541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
6051541Srgrimes
60699797Sdillon	*retdirp = NULL;
607105481Srwatson	cnp->cn_flags |= NOMACCHECK;
60892783Sjeff	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
60929653Sdyson
6101541Srgrimes	/*
6111541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
6121541Srgrimes	 * and set the various ndp fields appropriately.
6131541Srgrimes	 */
6141541Srgrimes	fromcp = *dposp;
6151541Srgrimes	tocp = cnp->cn_pnbuf;
6161541Srgrimes	md = *mdp;
6171541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
6181541Srgrimes	for (i = 0; i < len; i++) {
6191541Srgrimes		while (rem == 0) {
6201541Srgrimes			md = md->m_next;
6211541Srgrimes			if (md == NULL) {
6221541Srgrimes				error = EBADRPC;
6231541Srgrimes				goto out;
6241541Srgrimes			}
6251541Srgrimes			fromcp = mtod(md, caddr_t);
6261541Srgrimes			rem = md->m_len;
6271541Srgrimes		}
62827446Sdfr		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
6299336Sdfr			error = EACCES;
6301541Srgrimes			goto out;
6311541Srgrimes		}
6321541Srgrimes		*tocp++ = *fromcp++;
6331541Srgrimes		rem--;
6341541Srgrimes	}
6351541Srgrimes	*tocp = '\0';
6361541Srgrimes	*mdp = md;
6371541Srgrimes	*dposp = fromcp;
6381541Srgrimes	len = nfsm_rndup(len)-len;
6391541Srgrimes	if (len > 0) {
6401541Srgrimes		if (rem >= len)
6411541Srgrimes			*dposp += len;
64227609Sdfr		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
6439336Sdfr			goto out;
6441541Srgrimes	}
64527446Sdfr
6461541Srgrimes	/*
6471541Srgrimes	 * Extract and set starting directory.
6481541Srgrimes	 */
64927446Sdfr	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
65083651Speter	    nam, &rdonly, pubflag);
65127446Sdfr	if (error)
6521541Srgrimes		goto out;
6531541Srgrimes	if (dp->v_type != VDIR) {
65417761Sdyson		vrele(dp);
6551541Srgrimes		error = ENOTDIR;
6561541Srgrimes		goto out;
6571541Srgrimes	}
65827446Sdfr
65927446Sdfr	if (rdonly)
66027446Sdfr		cnp->cn_flags |= RDONLY;
66127446Sdfr
66248125Sjulian	/*
66383651Speter	 * Set return directory.  Reference to dp is implicitly transfered
66448125Sjulian	 * to the returned pointer
66548125Sjulian	 */
66627609Sdfr	*retdirp = dp;
66727609Sdfr
66827446Sdfr	if (pubflag) {
66927446Sdfr		/*
67027446Sdfr		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
67127446Sdfr		 * and the 'native path' indicator.
67227446Sdfr		 */
67392783Sjeff		cp = uma_zalloc(namei_zone, M_WAITOK);
67427446Sdfr		fromcp = cnp->cn_pnbuf;
67527446Sdfr		tocp = cp;
67627446Sdfr		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
67727446Sdfr			switch ((unsigned char)*fromcp) {
67827446Sdfr			case WEBNFS_NATIVE_CHAR:
67927446Sdfr				/*
68027446Sdfr				 * 'Native' path for us is the same
68127446Sdfr				 * as a path according to the NFS spec,
68227446Sdfr				 * just skip the escape char.
68327446Sdfr				 */
68427446Sdfr				fromcp++;
68527446Sdfr				break;
68627446Sdfr			/*
68727446Sdfr			 * More may be added in the future, range 0x80-0xff
68827446Sdfr			 */
68927446Sdfr			default:
69027446Sdfr				error = EIO;
69192783Sjeff				uma_zfree(namei_zone, cp);
69227446Sdfr				goto out;
69327446Sdfr			}
69427446Sdfr		}
69527446Sdfr		/*
69627446Sdfr		 * Translate the '%' escapes, URL-style.
69727446Sdfr		 */
69827446Sdfr		while (*fromcp != '\0') {
69927446Sdfr			if (*fromcp == WEBNFS_ESC_CHAR) {
70027446Sdfr				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
70127446Sdfr					fromcp++;
70227446Sdfr					*tocp++ = HEXSTRTOI(fromcp);
70327446Sdfr					fromcp += 2;
70427446Sdfr					continue;
70527446Sdfr				} else {
70627446Sdfr					error = ENOENT;
70792783Sjeff					uma_zfree(namei_zone, cp);
70827446Sdfr					goto out;
70927446Sdfr				}
71027446Sdfr			} else
71127446Sdfr				*tocp++ = *fromcp++;
71227446Sdfr		}
71327446Sdfr		*tocp = '\0';
71492783Sjeff		uma_zfree(namei_zone, cnp->cn_pnbuf);
71527446Sdfr		cnp->cn_pnbuf = cp;
71627446Sdfr	}
71727446Sdfr
71827446Sdfr	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
71927446Sdfr	ndp->ni_segflg = UIO_SYSSPACE;
72027446Sdfr
72127446Sdfr	if (pubflag) {
72227446Sdfr		ndp->ni_rootdir = rootvnode;
72327446Sdfr		ndp->ni_loopcnt = 0;
72427446Sdfr		if (cnp->cn_pnbuf[0] == '/')
72527446Sdfr			dp = rootvnode;
72627446Sdfr	} else {
72727609Sdfr		cnp->cn_flags |= NOCROSSMOUNT;
72827446Sdfr	}
72927446Sdfr
73048125Sjulian	/*
73148125Sjulian	 * Initialize for scan, set ni_startdir and bump ref on dp again
73248125Sjulian	 * becuase lookup() will dereference ni_startdir.
73348125Sjulian	 */
73448125Sjulian
73583366Sjulian	cnp->cn_thread = td;
7369336Sdfr	VREF(dp);
73748125Sjulian	ndp->ni_startdir = dp;
73827446Sdfr
73948125Sjulian	for (;;) {
74048125Sjulian		cnp->cn_nameptr = cnp->cn_pnbuf;
74148125Sjulian		/*
74248125Sjulian		 * Call lookup() to do the real work.  If an error occurs,
74348125Sjulian		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
74448125Sjulian		 * we do not have to dereference anything before returning.
74548125Sjulian		 * In either case ni_startdir will be dereferenced and NULLed
74648125Sjulian		 * out.
74748125Sjulian		 */
74848125Sjulian		error = lookup(ndp);
74948125Sjulian		if (error)
75048125Sjulian			break;
75148125Sjulian
75248125Sjulian		/*
75383651Speter		 * Check for encountering a symbolic link.  Trivial
75448125Sjulian		 * termination occurs if no symlink encountered.
75548125Sjulian		 * Note: zfree is safe because error is 0, so we will
75648125Sjulian		 * not zfree it again when we break.
75748125Sjulian		 */
75848125Sjulian		if ((cnp->cn_flags & ISSYMLINK) == 0) {
75948125Sjulian			nfsrv_object_create(ndp->ni_vp);
76048125Sjulian			if (cnp->cn_flags & (SAVENAME | SAVESTART))
76148125Sjulian				cnp->cn_flags |= HASBUF;
76248125Sjulian			else
76392783Sjeff				uma_zfree(namei_zone, cnp->cn_pnbuf);
76448125Sjulian			break;
76527446Sdfr		}
76648125Sjulian
76748125Sjulian		/*
76848125Sjulian		 * Validate symlink
76948125Sjulian		 */
7701541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
77183366Sjulian			VOP_UNLOCK(ndp->ni_dvp, 0, td);
77227446Sdfr		if (!pubflag) {
77327446Sdfr			error = EINVAL;
77448125Sjulian			goto badlink2;
77527446Sdfr		}
77627446Sdfr
77727446Sdfr		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
77827446Sdfr			error = ELOOP;
77948125Sjulian			goto badlink2;
78027446Sdfr		}
78127609Sdfr		if (ndp->ni_pathlen > 1)
78292783Sjeff			cp = uma_zalloc(namei_zone, M_WAITOK);
7831541Srgrimes		else
78427446Sdfr			cp = cnp->cn_pnbuf;
78527446Sdfr		aiov.iov_base = cp;
78627446Sdfr		aiov.iov_len = MAXPATHLEN;
78727446Sdfr		auio.uio_iov = &aiov;
78827446Sdfr		auio.uio_iovcnt = 1;
78927446Sdfr		auio.uio_offset = 0;
79027446Sdfr		auio.uio_rw = UIO_READ;
79127446Sdfr		auio.uio_segflg = UIO_SYSSPACE;
79299797Sdillon		auio.uio_td = NULL;
79327446Sdfr		auio.uio_resid = MAXPATHLEN;
79427446Sdfr		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
79527446Sdfr		if (error) {
79648125Sjulian		badlink1:
79727446Sdfr			if (ndp->ni_pathlen > 1)
79892783Sjeff				uma_zfree(namei_zone, cp);
79948125Sjulian		badlink2:
80048125Sjulian			vrele(ndp->ni_dvp);
80148125Sjulian			vput(ndp->ni_vp);
80227446Sdfr			break;
80327446Sdfr		}
80427446Sdfr		linklen = MAXPATHLEN - auio.uio_resid;
80527446Sdfr		if (linklen == 0) {
80627446Sdfr			error = ENOENT;
80748125Sjulian			goto badlink1;
80827446Sdfr		}
80927446Sdfr		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
81027446Sdfr			error = ENAMETOOLONG;
81148125Sjulian			goto badlink1;
81227446Sdfr		}
81348125Sjulian
81448125Sjulian		/*
81548125Sjulian		 * Adjust or replace path
81648125Sjulian		 */
81727446Sdfr		if (ndp->ni_pathlen > 1) {
81827446Sdfr			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
81992783Sjeff			uma_zfree(namei_zone, cnp->cn_pnbuf);
82027446Sdfr			cnp->cn_pnbuf = cp;
82127446Sdfr		} else
82227446Sdfr			cnp->cn_pnbuf[linklen] = '\0';
82327446Sdfr		ndp->ni_pathlen += linklen;
82448125Sjulian
82527446Sdfr		/*
82683651Speter		 * Cleanup refs for next loop and check if root directory
82783651Speter		 * should replace current directory.  Normally ni_dvp
82848125Sjulian		 * becomes the new base directory and is cleaned up when
82948125Sjulian		 * we loop.  Explicitly null pointers after invalidation
83048125Sjulian		 * to clarify operation.
83127446Sdfr		 */
83248125Sjulian		vput(ndp->ni_vp);
83348125Sjulian		ndp->ni_vp = NULL;
83448125Sjulian
83527446Sdfr		if (cnp->cn_pnbuf[0] == '/') {
83648125Sjulian			vrele(ndp->ni_dvp);
83748125Sjulian			ndp->ni_dvp = ndp->ni_rootdir;
83848125Sjulian			VREF(ndp->ni_dvp);
83927446Sdfr		}
84048125Sjulian		ndp->ni_startdir = ndp->ni_dvp;
84148125Sjulian		ndp->ni_dvp = NULL;
8421541Srgrimes	}
84348125Sjulian
84448125Sjulian	/*
84548125Sjulian	 * nfs_namei() guarentees that fields will not contain garbage
84648125Sjulian	 * whether an error occurs or not.  This allows the caller to track
84748125Sjulian	 * cleanup state trivially.
84848125Sjulian	 */
8491541Srgrimesout:
85048125Sjulian	if (error) {
85192783Sjeff		uma_zfree(namei_zone, cnp->cn_pnbuf);
85248125Sjulian		ndp->ni_vp = NULL;
85348125Sjulian		ndp->ni_dvp = NULL;
85448125Sjulian		ndp->ni_startdir = NULL;
85548125Sjulian		cnp->cn_flags &= ~HASBUF;
85648125Sjulian	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
85748125Sjulian		ndp->ni_dvp = NULL;
85848125Sjulian	}
8591541Srgrimes	return (error);
8601541Srgrimes}
8611541Srgrimes
8621541Srgrimes/*
8631541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
8641541Srgrimes * boundary and only trims off the back end
8651541Srgrimes */
8661541Srgrimesvoid
86783651Speternfsm_adj(struct mbuf *mp, int len, int nul)
8681541Srgrimes{
86983651Speter	struct mbuf *m;
87083651Speter	int count, i;
87183651Speter	char *cp;
8721541Srgrimes
8731541Srgrimes	/*
8741541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
8751541Srgrimes	 * calculating its length and finding the last mbuf.
8761541Srgrimes	 * If the adjustment only affects this mbuf, then just
8771541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
8781541Srgrimes	 * after the remaining size.
8791541Srgrimes	 */
8801541Srgrimes	count = 0;
8811541Srgrimes	m = mp;
8821541Srgrimes	for (;;) {
8831541Srgrimes		count += m->m_len;
88499797Sdillon		if (m->m_next == NULL)
8851541Srgrimes			break;
8861541Srgrimes		m = m->m_next;
8871541Srgrimes	}
8881541Srgrimes	if (m->m_len > len) {
8891541Srgrimes		m->m_len -= len;
8901541Srgrimes		if (nul > 0) {
8911541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
8921541Srgrimes			for (i = 0; i < nul; i++)
8931541Srgrimes				*cp++ = '\0';
8941541Srgrimes		}
8951541Srgrimes		return;
8961541Srgrimes	}
8971541Srgrimes	count -= len;
8981541Srgrimes	if (count < 0)
8991541Srgrimes		count = 0;
9001541Srgrimes	/*
9011541Srgrimes	 * Correct length for chain is "count".
9021541Srgrimes	 * Find the mbuf with last data, adjust its length,
9031541Srgrimes	 * and toss data from remaining mbufs on chain.
9041541Srgrimes	 */
9051541Srgrimes	for (m = mp; m; m = m->m_next) {
9061541Srgrimes		if (m->m_len >= count) {
9071541Srgrimes			m->m_len = count;
9081541Srgrimes			if (nul > 0) {
9091541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
9101541Srgrimes				for (i = 0; i < nul; i++)
9111541Srgrimes					*cp++ = '\0';
9121541Srgrimes			}
9131541Srgrimes			break;
9141541Srgrimes		}
9151541Srgrimes		count -= m->m_len;
9161541Srgrimes	}
9173305Sphk	for (m = m->m_next;m;m = m->m_next)
9181541Srgrimes		m->m_len = 0;
9191541Srgrimes}
9201541Srgrimes
9211541Srgrimes/*
9229336Sdfr * Make these functions instead of macros, so that the kernel text size
9239336Sdfr * doesn't get too big...
9249336Sdfr */
9259336Sdfrvoid
92683651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
92783651Speter    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
92883651Speter    struct mbuf **mbp, char **bposp)
9299336Sdfr{
93083651Speter	struct mbuf *mb = *mbp;
93183651Speter	char *bpos = *bposp;
93283651Speter	u_int32_t *tl;
9339336Sdfr
9349336Sdfr	if (before_ret) {
93584002Speter		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
93689094Smsmith		*tl = nfsrv_nfs_false;
9379336Sdfr	} else {
93884002Speter		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
93989094Smsmith		*tl++ = nfsrv_nfs_true;
94047751Speter		txdr_hyper(before_vap->va_size, tl);
9419336Sdfr		tl += 2;
9429336Sdfr		txdr_nfsv3time(&(before_vap->va_mtime), tl);
9439336Sdfr		tl += 2;
9449336Sdfr		txdr_nfsv3time(&(before_vap->va_ctime), tl);
9459336Sdfr	}
9469336Sdfr	*bposp = bpos;
9479336Sdfr	*mbp = mb;
9489336Sdfr	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
9499336Sdfr}
9509336Sdfr
9519336Sdfrvoid
95283651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
95383651Speter    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
9549336Sdfr{
95583651Speter	struct mbuf *mb = *mbp;
95683651Speter	char *bpos = *bposp;
95783651Speter	u_int32_t *tl;
95883651Speter	struct nfs_fattr *fp;
9599336Sdfr
9609336Sdfr	if (after_ret) {
96184002Speter		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
96289094Smsmith		*tl = nfsrv_nfs_false;
9639336Sdfr	} else {
96484002Speter		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
96589094Smsmith		*tl++ = nfsrv_nfs_true;
9669336Sdfr		fp = (struct nfs_fattr *)tl;
9679336Sdfr		nfsm_srvfattr(nfsd, after_vap, fp);
9689336Sdfr	}
9699336Sdfr	*mbp = mb;
9709336Sdfr	*bposp = bpos;
9719336Sdfr}
9729336Sdfr
9739336Sdfrvoid
97483651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
97583651Speter    struct nfs_fattr *fp)
9769336Sdfr{
9779336Sdfr
9789336Sdfr	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
9799336Sdfr	fp->fa_uid = txdr_unsigned(vap->va_uid);
9809336Sdfr	fp->fa_gid = txdr_unsigned(vap->va_gid);
9819336Sdfr	if (nfsd->nd_flag & ND_NFSV3) {
9829336Sdfr		fp->fa_type = vtonfsv3_type(vap->va_type);
9839336Sdfr		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
98447751Speter		txdr_hyper(vap->va_size, &fp->fa3_size);
98547751Speter		txdr_hyper(vap->va_bytes, &fp->fa3_used);
98647028Sphk		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
98747028Sphk		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
9889336Sdfr		fp->fa3_fsid.nfsuquad[0] = 0;
9899336Sdfr		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
9909336Sdfr		fp->fa3_fileid.nfsuquad[0] = 0;
9919336Sdfr		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
9929336Sdfr		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
9939336Sdfr		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
9949336Sdfr		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
9959336Sdfr	} else {
9969336Sdfr		fp->fa_type = vtonfsv2_type(vap->va_type);
9979336Sdfr		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
9989336Sdfr		fp->fa2_size = txdr_unsigned(vap->va_size);
9999336Sdfr		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
10009336Sdfr		if (vap->va_type == VFIFO)
10019336Sdfr			fp->fa2_rdev = 0xffffffff;
10029336Sdfr		else
10039336Sdfr			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
10049336Sdfr		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
10059336Sdfr		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
10069336Sdfr		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
10079336Sdfr		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
10089336Sdfr		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
10099336Sdfr		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
10109336Sdfr	}
10119336Sdfr}
10129336Sdfr
10139336Sdfr/*
10141541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
10151541Srgrimes * 	- look up fsid in mount list (if not found ret error)
10161541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
10171541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
10181541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
10191541Srgrimes */
10201549Srgrimesint
102183651Speternfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
102283651Speter    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
102383651Speter    int *rdonlyp, int pubflag)
10241541Srgrimes{
102583366Sjulian	struct thread *td = curthread; /* XXX */
102683651Speter	struct mount *mp;
102783651Speter	int i;
10281541Srgrimes	struct ucred *credanon;
10291541Srgrimes	int error, exflags;
103036534Speter#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
103136534Speter	struct sockaddr_int *saddr;
103236534Speter#endif
10331541Srgrimes
103499797Sdillon	*vpp = NULL;
103527446Sdfr
103627446Sdfr	if (nfs_ispublicfh(fhp)) {
103727446Sdfr		if (!pubflag || !nfs_pub.np_valid)
103827446Sdfr			return (ESTALE);
103927446Sdfr		fhp = &nfs_pub.np_handle;
104027446Sdfr	}
104127446Sdfr
104222521Sdyson	mp = vfs_getvfs(&fhp->fh_fsid);
10433305Sphk	if (!mp)
10441541Srgrimes		return (ESTALE);
104551138Salfred	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
10463305Sphk	if (error)
104783651Speter		return (error);
104851138Salfred	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
104951138Salfred	if (error)
10501541Srgrimes		return (error);
105136534Speter#ifdef MNT_EXNORESPORT
105236534Speter	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
105336534Speter		saddr = (struct sockaddr_in *)nam;
1054100134Salfred		if ((saddr->sin_family == AF_INET ||
1055100134Salfred		     saddr->sin_family == AF_INET6) &&
1056100134Salfred	/* same code for INET and INET6: sin*_port at same offet */
105736534Speter		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
105836534Speter			vput(*vpp);
105954485Sdillon			*vpp = NULL;
106036534Speter			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
106136534Speter		}
106236534Speter	}
106336534Speter#endif
10641541Srgrimes	/*
10651541Srgrimes	 * Check/setup credentials.
10661541Srgrimes	 */
106783651Speter	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
10681541Srgrimes		cred->cr_uid = credanon->cr_uid;
10691541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
10701541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
10713664Sphk		cred->cr_ngroups = i;
10721541Srgrimes	}
10731541Srgrimes	if (exflags & MNT_EXRDONLY)
10741541Srgrimes		*rdonlyp = 1;
10751541Srgrimes	else
10761541Srgrimes		*rdonlyp = 0;
10777969Sdyson
107817761Sdyson	nfsrv_object_create(*vpp);
10797969Sdyson
10801541Srgrimes	if (!lockflag)
108183366Sjulian		VOP_UNLOCK(*vpp, 0, td);
10821541Srgrimes	return (0);
10831541Srgrimes}
10841541Srgrimes
108527446Sdfr
108627446Sdfr/*
108727446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this
108827446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
108927446Sdfr * transformed this to all zeroes in both cases, so check for it.
109027446Sdfr */
109127446Sdfrint
109283651Speternfs_ispublicfh(fhandle_t *fhp)
109327446Sdfr{
109427446Sdfr	char *cp = (char *)fhp;
109527446Sdfr	int i;
109627446Sdfr
109727446Sdfr	for (i = 0; i < NFSX_V3FH; i++)
109827446Sdfr		if (*cp++ != 0)
109927446Sdfr			return (FALSE);
110027446Sdfr	return (TRUE);
110127446Sdfr}
110283651Speter
11031541Srgrimes/*
11041541Srgrimes * This function compares two net addresses by family and returns TRUE
11051541Srgrimes * if they are the same host.
11061541Srgrimes * If there is any doubt, return FALSE.
11071541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
11081541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
11091541Srgrimes */
11101549Srgrimesint
111183651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
11121541Srgrimes{
111383651Speter	struct sockaddr_in *inetaddr;
11141541Srgrimes
11151541Srgrimes	switch (family) {
11161541Srgrimes	case AF_INET:
111728270Swollman		inetaddr = (struct sockaddr_in *)nam;
11181541Srgrimes		if (inetaddr->sin_family == AF_INET &&
11191541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
11201541Srgrimes			return (1);
11211541Srgrimes		break;
1122100134Salfred#ifdef INET6
1123100134Salfred	case AF_INET6:
1124100134Salfred	{
1125100134Salfred		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1126100134Salfred
1127100134Salfred		inet6addr1 = (struct sockaddr_in6 *)nam;
1128100134Salfred		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1129100134Salfred	/* XXX - should test sin6_scope_id ? */
1130100134Salfred		if (inet6addr1->sin6_family == AF_INET6 &&
1131100134Salfred		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1132100134Salfred				       &inet6addr2->sin6_addr))
1133100134Salfred			return (1);
1134100134Salfred		break;
1135100134Salfred	}
1136100134Salfred#endif
11371541Srgrimes	default:
11381541Srgrimes		break;
11391541Srgrimes	};
11401541Srgrimes	return (0);
11411541Srgrimes}
11425455Sdg
11439336Sdfr/*
11449336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error
11459336Sdfr * numbers not specified for the associated procedure.
11469336Sdfr */
11475455Sdgint
114883651Speternfsrv_errmap(struct nfsrv_descript *nd, int err)
11499336Sdfr{
115083651Speter	short *defaulterrp, *errp;
1151102236Sphk	int e;
11529336Sdfr
11539336Sdfr	if (nd->nd_flag & ND_NFSV3) {
11549336Sdfr	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
11559336Sdfr		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
11569336Sdfr		while (*++errp) {
11579336Sdfr			if (*errp == err)
11589336Sdfr				return (err);
11599336Sdfr			else if (*errp > err)
11609336Sdfr				break;
11619336Sdfr		}
11629336Sdfr		return ((int)*defaulterrp);
11639336Sdfr	    } else
11649336Sdfr		return (err & 0xffff);
11659336Sdfr	}
1166102236Sphk	e = 0;
11679336Sdfr	if (err <= ELAST)
1168102236Sphk		e = nfsrv_v2errmap[err - 1];
1169102236Sphk	if (e != 0)
1170102236Sphk		return (e);
11719336Sdfr	return (NFSERR_IO);
11729336Sdfr}
11739336Sdfr
11749336Sdfrint
117583651Speternfsrv_object_create(struct vnode *vp)
117631886Sbde{
11775455Sdg
117831886Sbde	if (vp == NULL || vp->v_type != VREG)
117931886Sbde		return (1);
118091406Sjhb	return (vfs_object_create(vp, curthread, curthread->td_ucred));
11815455Sdg}
118236503Speter
118336503Speter/*
118436503Speter * Sort the group list in increasing numerical order.
118536503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
118636503Speter *  that used to be here.)
118736503Speter */
118836503Spetervoid
118983651Speternfsrvw_sort(gid_t *list, int num)
119036503Speter{
119183651Speter	int i, j;
119236503Speter	gid_t v;
119336503Speter
119436503Speter	/* Insertion sort. */
119536503Speter	for (i = 1; i < num; i++) {
119636503Speter		v = list[i];
119736503Speter		/* find correct slot for value v, moving others up */
119836503Speter		for (j = i; --j >= 0 && v < list[j];)
119936503Speter			list[j + 1] = list[j];
120036503Speter		list[j + 1] = v;
120136503Speter	}
120236503Speter}
120336503Speter
120436503Speter/*
120536503Speter * copy credentials making sure that the result can be compared with bcmp().
120636503Speter */
120736503Spetervoid
120883651Speternfsrv_setcred(struct ucred *incred, struct ucred *outcred)
120936503Speter{
121083651Speter	int i;
121136503Speter
121236503Speter	bzero((caddr_t)outcred, sizeof (struct ucred));
121336503Speter	outcred->cr_ref = 1;
121436503Speter	outcred->cr_uid = incred->cr_uid;
121536503Speter	outcred->cr_ngroups = incred->cr_ngroups;
121636503Speter	for (i = 0; i < incred->cr_ngroups; i++)
121736503Speter		outcred->cr_groups[i] = incred->cr_groups[i];
121836503Speter	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
121936503Speter}
122083651Speter
122183651Speter/*
122283651Speter * Helper functions for macros.
122383651Speter */
122483651Speter
122583651Spetervoid
122688091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
122783651Speter{
122888091Siedowse	u_int32_t *tl;
122983651Speter
123083651Speter	if (v3) {
123188091Siedowse		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
123288091Siedowse		*tl++ = txdr_unsigned(NFSX_V3FH);
123388091Siedowse		bcopy(f, tl, NFSX_V3FH);
123483651Speter	} else {
123588091Siedowse		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
123688091Siedowse		bcopy(f, tl, NFSX_V2FH);
123783651Speter	}
123883651Speter}
123983651Speter
124083651Spetervoid
124188091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
124283651Speter{
124388091Siedowse	u_int32_t *tl;
124484002Speter
124588091Siedowse	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
124689094Smsmith	*tl++ = nfsrv_nfs_true;
124788091Siedowse	*tl++ = txdr_unsigned(NFSX_V3FH);
124888091Siedowse	bcopy(f, tl, NFSX_V3FH);
124983651Speter}
125083651Speter
125183651Speterint
125288091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
125383651Speter{
125488091Siedowse	u_int32_t *tl;
125583651Speter
125688091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
125788091Siedowse	if (tl == NULL)
125884057Speter		return EBADRPC;
125988091Siedowse	*s = fxdr_unsigned(int32_t, *tl);
126083651Speter	if (*s > m || *s <= 0)
126183651Speter		return EBADRPC;
126283651Speter	return 0;
126383651Speter}
126483651Speter
126583651Speterint
1266106264Sjeffnfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
126783651Speter{
126888091Siedowse	u_int32_t *tl;
126983651Speter
127088091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
127188091Siedowse	if (tl == NULL)
127284057Speter		return EBADRPC;
127388091Siedowse	*s = fxdr_unsigned(int32_t, *tl);
1274106264Sjeff	if (*s > m)
127583651Speter		return NFSERR_NAMETOL;
127683651Speter	if (*s <= 0)
127783651Speter		return EBADRPC;
127883651Speter	return 0;
127983651Speter}
128083651Speter
128183651Spetervoid
128283651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
128383651Speter    char **bp, char **be, caddr_t bpos)
128483651Speter{
128583651Speter	struct mbuf *nmp;
128683651Speter
128783651Speter	if (*bp >= *be) {
128883651Speter		if (*mp == mb)
128983651Speter			(*mp)->m_len += *bp - bpos;
129083651Speter		MGET(nmp, M_TRYWAIT, MT_DATA);
129183651Speter		MCLGET(nmp, M_TRYWAIT);
129283651Speter		nmp->m_len = NFSMSIZ(nmp);
129383651Speter		(*mp)->m_next = nmp;
129483651Speter		*mp = nmp;
129583651Speter		*bp = mtod(*mp, caddr_t);
129683651Speter		*be = *bp + (*mp)->m_len;
129783651Speter	}
129883651Speter	*tl = (u_int32_t *)*bp;
129983651Speter}
130083651Speter
130183651Speterint
130288091Siedowsenfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
130388091Siedowse    caddr_t *dpos)
130483651Speter{
130588091Siedowse	u_int32_t *tl;
130683651Speter	int fhlen;
130783651Speter
130883651Speter	if (nfsd->nd_flag & ND_NFSV3) {
130988091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
131088091Siedowse		if (tl == NULL)
131184057Speter			return EBADRPC;
131288091Siedowse		fhlen = fxdr_unsigned(int, *tl);
131383651Speter		if (fhlen != 0 && fhlen != NFSX_V3FH)
131483651Speter			return EBADRPC;
131583651Speter	} else {
131683651Speter		fhlen = NFSX_V2FH;
131783651Speter	}
131883651Speter	if (fhlen != 0) {
131988091Siedowse		tl = nfsm_dissect_xx(fhlen, md, dpos);
132088091Siedowse		if (tl == NULL)
132184057Speter			return EBADRPC;
132288091Siedowse		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
132383651Speter	} else {
132483651Speter		bzero((caddr_t)(f), NFSX_V3FH);
132583651Speter	}
132683651Speter	return 0;
132783651Speter}
132883651Speter
132983651Speterint
133088091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
133183651Speter{
133288091Siedowse	u_int32_t *tl;
133383651Speter
133488091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
133588091Siedowse	if (tl == NULL)
133684057Speter		return EBADRPC;
133789094Smsmith	if (*tl == nfsrv_nfs_true) {
133888091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
133988091Siedowse		if (tl == NULL)
134084057Speter			return EBADRPC;
134188091Siedowse		(a)->va_mode = nfstov_mode(*tl);
134283651Speter	}
134388091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
134488091Siedowse	if (tl == NULL)
134584057Speter		return EBADRPC;
134689094Smsmith	if (*tl == nfsrv_nfs_true) {
134788091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
134888091Siedowse		if (tl == NULL)
134984057Speter			return EBADRPC;
135088091Siedowse		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
135183651Speter	}
135288091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
135388091Siedowse	if (tl == NULL)
135484057Speter		return EBADRPC;
135589094Smsmith	if (*tl == nfsrv_nfs_true) {
135688091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
135788091Siedowse		if (tl == NULL)
135884057Speter			return EBADRPC;
135988091Siedowse		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
136083651Speter	}
136188091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
136288091Siedowse	if (tl == NULL)
136384057Speter		return EBADRPC;
136489094Smsmith	if (*tl == nfsrv_nfs_true) {
136588091Siedowse		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
136688091Siedowse		if (tl == NULL)
136784057Speter			return EBADRPC;
136888091Siedowse		(a)->va_size = fxdr_hyper(tl);
136983651Speter	}
137088091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
137188091Siedowse	if (tl == NULL)
137284057Speter		return EBADRPC;
137388091Siedowse	switch (fxdr_unsigned(int, *tl)) {
137483651Speter	case NFSV3SATTRTIME_TOCLIENT:
137588091Siedowse		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
137688091Siedowse		if (tl == NULL)
137784057Speter			return EBADRPC;
137888091Siedowse		fxdr_nfsv3time(tl, &(a)->va_atime);
137983651Speter		break;
138083651Speter	case NFSV3SATTRTIME_TOSERVER:
138183651Speter		getnanotime(&(a)->va_atime);
138283651Speter		break;
138383651Speter	}
138488091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
138588091Siedowse	if (tl == NULL)
138684057Speter		return EBADRPC;
138788091Siedowse	switch (fxdr_unsigned(int, *tl)) {
138883651Speter	case NFSV3SATTRTIME_TOCLIENT:
138988091Siedowse		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
139088091Siedowse		if (tl == NULL)
139184057Speter			return EBADRPC;
139288091Siedowse		fxdr_nfsv3time(tl, &(a)->va_mtime);
139383651Speter		break;
139483651Speter	case NFSV3SATTRTIME_TOSERVER:
139583651Speter		getnanotime(&(a)->va_mtime);
139683651Speter		break;
139783651Speter	}
139883651Speter	return 0;
139983651Speter}
1400