nfs_srvsubs.c revision 100134
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 100134 2002-07-15 19:40:23Z alfred $ 381541Srgrimes */ 391541Srgrimes 4083651Speter#include <sys/cdefs.h> 4183651Speter__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 100134 2002-07-15 19:40:23Z alfred $"); 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. 1689336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1699336Sdfr * RFC 1094. 1709336Sdfr */ 1719336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1729336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1739336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1749336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1759336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 1769336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1779336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 1789336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1799336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1809336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1819336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1829336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1839336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1849336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 1859336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 1869336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1879336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 18841796Sdt NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 18941796Sdt NFSERR_IO /* << Last is 86 */ 1909336Sdfr}; 1919336Sdfr 1929336Sdfr/* 1939336Sdfr * Maps errno values to nfs error numbers. 1949336Sdfr * Although it is not obvious whether or not NFS clients really care if 1959336Sdfr * a returned error value is in the specified list for the procedure, the 1969336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 1979336Sdfr * X/Open XNFS document is the only specification that defines error values 1989336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 1999336Sdfr * so I have decided to not do this for Version 2. 2009336Sdfr * The first entry is the default error return and the rest are the valid 2019336Sdfr * errors for that RPC in increasing numeric order. 2029336Sdfr */ 2039336Sdfrstatic short nfsv3err_null[] = { 2049336Sdfr 0, 2059336Sdfr 0, 2069336Sdfr}; 2079336Sdfr 2089336Sdfrstatic short nfsv3err_getattr[] = { 2099336Sdfr NFSERR_IO, 2109336Sdfr NFSERR_IO, 2119336Sdfr NFSERR_STALE, 2129336Sdfr NFSERR_BADHANDLE, 2139336Sdfr NFSERR_SERVERFAULT, 2149336Sdfr 0, 2159336Sdfr}; 2169336Sdfr 2179336Sdfrstatic short nfsv3err_setattr[] = { 2189336Sdfr NFSERR_IO, 2199336Sdfr NFSERR_PERM, 2209336Sdfr NFSERR_IO, 2219336Sdfr NFSERR_ACCES, 2229336Sdfr NFSERR_INVAL, 2239336Sdfr NFSERR_NOSPC, 2249336Sdfr NFSERR_ROFS, 2259336Sdfr NFSERR_DQUOT, 2269336Sdfr NFSERR_STALE, 2279336Sdfr NFSERR_BADHANDLE, 2289336Sdfr NFSERR_NOT_SYNC, 2299336Sdfr NFSERR_SERVERFAULT, 2309336Sdfr 0, 2319336Sdfr}; 2329336Sdfr 2339336Sdfrstatic short nfsv3err_lookup[] = { 2349336Sdfr NFSERR_IO, 2359336Sdfr NFSERR_NOENT, 2369336Sdfr NFSERR_IO, 2379336Sdfr NFSERR_ACCES, 2389336Sdfr NFSERR_NOTDIR, 2399336Sdfr NFSERR_NAMETOL, 2409336Sdfr NFSERR_STALE, 2419336Sdfr NFSERR_BADHANDLE, 2429336Sdfr NFSERR_SERVERFAULT, 2439336Sdfr 0, 2449336Sdfr}; 2459336Sdfr 2469336Sdfrstatic short nfsv3err_access[] = { 2479336Sdfr NFSERR_IO, 2489336Sdfr NFSERR_IO, 2499336Sdfr NFSERR_STALE, 2509336Sdfr NFSERR_BADHANDLE, 2519336Sdfr NFSERR_SERVERFAULT, 2529336Sdfr 0, 2539336Sdfr}; 2549336Sdfr 2559336Sdfrstatic short nfsv3err_readlink[] = { 2569336Sdfr NFSERR_IO, 2579336Sdfr NFSERR_IO, 2589336Sdfr NFSERR_ACCES, 2599336Sdfr NFSERR_INVAL, 2609336Sdfr NFSERR_STALE, 2619336Sdfr NFSERR_BADHANDLE, 2629336Sdfr NFSERR_NOTSUPP, 2639336Sdfr NFSERR_SERVERFAULT, 2649336Sdfr 0, 2659336Sdfr}; 2669336Sdfr 2679336Sdfrstatic short nfsv3err_read[] = { 2689336Sdfr NFSERR_IO, 2699336Sdfr NFSERR_IO, 2709336Sdfr NFSERR_NXIO, 2719336Sdfr NFSERR_ACCES, 2729336Sdfr NFSERR_INVAL, 2739336Sdfr NFSERR_STALE, 2749336Sdfr NFSERR_BADHANDLE, 2759336Sdfr NFSERR_SERVERFAULT, 2769336Sdfr 0, 2779336Sdfr}; 2789336Sdfr 2799336Sdfrstatic short nfsv3err_write[] = { 2809336Sdfr NFSERR_IO, 2819336Sdfr NFSERR_IO, 2829336Sdfr NFSERR_ACCES, 2839336Sdfr NFSERR_INVAL, 2849336Sdfr NFSERR_FBIG, 2859336Sdfr NFSERR_NOSPC, 2869336Sdfr NFSERR_ROFS, 2879336Sdfr NFSERR_DQUOT, 2889336Sdfr NFSERR_STALE, 2899336Sdfr NFSERR_BADHANDLE, 2909336Sdfr NFSERR_SERVERFAULT, 2919336Sdfr 0, 2929336Sdfr}; 2939336Sdfr 2949336Sdfrstatic short nfsv3err_create[] = { 2959336Sdfr NFSERR_IO, 2969336Sdfr NFSERR_IO, 2979336Sdfr NFSERR_ACCES, 2989336Sdfr NFSERR_EXIST, 2999336Sdfr NFSERR_NOTDIR, 3009336Sdfr NFSERR_NOSPC, 3019336Sdfr NFSERR_ROFS, 3029336Sdfr NFSERR_NAMETOL, 3039336Sdfr NFSERR_DQUOT, 3049336Sdfr NFSERR_STALE, 3059336Sdfr NFSERR_BADHANDLE, 3069336Sdfr NFSERR_NOTSUPP, 3079336Sdfr NFSERR_SERVERFAULT, 3089336Sdfr 0, 3099336Sdfr}; 3109336Sdfr 3119336Sdfrstatic short nfsv3err_mkdir[] = { 3129336Sdfr NFSERR_IO, 3139336Sdfr NFSERR_IO, 3149336Sdfr NFSERR_ACCES, 3159336Sdfr NFSERR_EXIST, 3169336Sdfr NFSERR_NOTDIR, 3179336Sdfr NFSERR_NOSPC, 3189336Sdfr NFSERR_ROFS, 3199336Sdfr NFSERR_NAMETOL, 3209336Sdfr NFSERR_DQUOT, 3219336Sdfr NFSERR_STALE, 3229336Sdfr NFSERR_BADHANDLE, 3239336Sdfr NFSERR_NOTSUPP, 3249336Sdfr NFSERR_SERVERFAULT, 3259336Sdfr 0, 3269336Sdfr}; 3279336Sdfr 3289336Sdfrstatic short nfsv3err_symlink[] = { 3299336Sdfr NFSERR_IO, 3309336Sdfr NFSERR_IO, 3319336Sdfr NFSERR_ACCES, 3329336Sdfr NFSERR_EXIST, 3339336Sdfr NFSERR_NOTDIR, 3349336Sdfr NFSERR_NOSPC, 3359336Sdfr NFSERR_ROFS, 3369336Sdfr NFSERR_NAMETOL, 3379336Sdfr NFSERR_DQUOT, 3389336Sdfr NFSERR_STALE, 3399336Sdfr NFSERR_BADHANDLE, 3409336Sdfr NFSERR_NOTSUPP, 3419336Sdfr NFSERR_SERVERFAULT, 3429336Sdfr 0, 3439336Sdfr}; 3449336Sdfr 3459336Sdfrstatic short nfsv3err_mknod[] = { 3469336Sdfr NFSERR_IO, 3479336Sdfr NFSERR_IO, 3489336Sdfr NFSERR_ACCES, 3499336Sdfr NFSERR_EXIST, 3509336Sdfr NFSERR_NOTDIR, 3519336Sdfr NFSERR_NOSPC, 3529336Sdfr NFSERR_ROFS, 3539336Sdfr NFSERR_NAMETOL, 3549336Sdfr NFSERR_DQUOT, 3559336Sdfr NFSERR_STALE, 3569336Sdfr NFSERR_BADHANDLE, 3579336Sdfr NFSERR_NOTSUPP, 3589336Sdfr NFSERR_SERVERFAULT, 3599336Sdfr NFSERR_BADTYPE, 3609336Sdfr 0, 3619336Sdfr}; 3629336Sdfr 3639336Sdfrstatic short nfsv3err_remove[] = { 3649336Sdfr NFSERR_IO, 3659336Sdfr NFSERR_NOENT, 3669336Sdfr NFSERR_IO, 3679336Sdfr NFSERR_ACCES, 3689336Sdfr NFSERR_NOTDIR, 3699336Sdfr NFSERR_ROFS, 3709336Sdfr NFSERR_NAMETOL, 3719336Sdfr NFSERR_STALE, 3729336Sdfr NFSERR_BADHANDLE, 3739336Sdfr NFSERR_SERVERFAULT, 3749336Sdfr 0, 3759336Sdfr}; 3769336Sdfr 3779336Sdfrstatic short nfsv3err_rmdir[] = { 3789336Sdfr NFSERR_IO, 3799336Sdfr NFSERR_NOENT, 3809336Sdfr NFSERR_IO, 3819336Sdfr NFSERR_ACCES, 3829336Sdfr NFSERR_EXIST, 3839336Sdfr NFSERR_NOTDIR, 3849336Sdfr NFSERR_INVAL, 3859336Sdfr NFSERR_ROFS, 3869336Sdfr NFSERR_NAMETOL, 3879336Sdfr NFSERR_NOTEMPTY, 3889336Sdfr NFSERR_STALE, 3899336Sdfr NFSERR_BADHANDLE, 3909336Sdfr NFSERR_NOTSUPP, 3919336Sdfr NFSERR_SERVERFAULT, 3929336Sdfr 0, 3939336Sdfr}; 3949336Sdfr 3959336Sdfrstatic short nfsv3err_rename[] = { 3969336Sdfr NFSERR_IO, 3979336Sdfr NFSERR_NOENT, 3989336Sdfr NFSERR_IO, 3999336Sdfr NFSERR_ACCES, 4009336Sdfr NFSERR_EXIST, 4019336Sdfr NFSERR_XDEV, 4029336Sdfr NFSERR_NOTDIR, 4039336Sdfr NFSERR_ISDIR, 4049336Sdfr NFSERR_INVAL, 4059336Sdfr NFSERR_NOSPC, 4069336Sdfr NFSERR_ROFS, 4079336Sdfr NFSERR_MLINK, 4089336Sdfr NFSERR_NAMETOL, 4099336Sdfr NFSERR_NOTEMPTY, 4109336Sdfr NFSERR_DQUOT, 4119336Sdfr NFSERR_STALE, 4129336Sdfr NFSERR_BADHANDLE, 4139336Sdfr NFSERR_NOTSUPP, 4149336Sdfr NFSERR_SERVERFAULT, 4159336Sdfr 0, 4169336Sdfr}; 4179336Sdfr 4189336Sdfrstatic short nfsv3err_link[] = { 4199336Sdfr NFSERR_IO, 4209336Sdfr NFSERR_IO, 4219336Sdfr NFSERR_ACCES, 4229336Sdfr NFSERR_EXIST, 4239336Sdfr NFSERR_XDEV, 4249336Sdfr NFSERR_NOTDIR, 4259336Sdfr NFSERR_INVAL, 4269336Sdfr NFSERR_NOSPC, 4279336Sdfr NFSERR_ROFS, 4289336Sdfr NFSERR_MLINK, 4299336Sdfr NFSERR_NAMETOL, 4309336Sdfr NFSERR_DQUOT, 4319336Sdfr NFSERR_STALE, 4329336Sdfr NFSERR_BADHANDLE, 4339336Sdfr NFSERR_NOTSUPP, 4349336Sdfr NFSERR_SERVERFAULT, 4359336Sdfr 0, 4369336Sdfr}; 4379336Sdfr 4389336Sdfrstatic short nfsv3err_readdir[] = { 4399336Sdfr NFSERR_IO, 4409336Sdfr NFSERR_IO, 4419336Sdfr NFSERR_ACCES, 4429336Sdfr NFSERR_NOTDIR, 4439336Sdfr NFSERR_STALE, 4449336Sdfr NFSERR_BADHANDLE, 4459336Sdfr NFSERR_BAD_COOKIE, 4469336Sdfr NFSERR_TOOSMALL, 4479336Sdfr NFSERR_SERVERFAULT, 4489336Sdfr 0, 4499336Sdfr}; 4509336Sdfr 4519336Sdfrstatic short nfsv3err_readdirplus[] = { 4529336Sdfr NFSERR_IO, 4539336Sdfr NFSERR_IO, 4549336Sdfr NFSERR_ACCES, 4559336Sdfr NFSERR_NOTDIR, 4569336Sdfr NFSERR_STALE, 4579336Sdfr NFSERR_BADHANDLE, 4589336Sdfr NFSERR_BAD_COOKIE, 4599336Sdfr NFSERR_NOTSUPP, 4609336Sdfr NFSERR_TOOSMALL, 4619336Sdfr NFSERR_SERVERFAULT, 4629336Sdfr 0, 4639336Sdfr}; 4649336Sdfr 4659336Sdfrstatic short nfsv3err_fsstat[] = { 4669336Sdfr NFSERR_IO, 4679336Sdfr NFSERR_IO, 4689336Sdfr NFSERR_STALE, 4699336Sdfr NFSERR_BADHANDLE, 4709336Sdfr NFSERR_SERVERFAULT, 4719336Sdfr 0, 4729336Sdfr}; 4739336Sdfr 4749336Sdfrstatic short nfsv3err_fsinfo[] = { 4759336Sdfr NFSERR_STALE, 4769336Sdfr NFSERR_STALE, 4779336Sdfr NFSERR_BADHANDLE, 4789336Sdfr NFSERR_SERVERFAULT, 4799336Sdfr 0, 4809336Sdfr}; 4819336Sdfr 4829336Sdfrstatic short nfsv3err_pathconf[] = { 4839336Sdfr NFSERR_STALE, 4849336Sdfr NFSERR_STALE, 4859336Sdfr NFSERR_BADHANDLE, 4869336Sdfr NFSERR_SERVERFAULT, 4879336Sdfr 0, 4889336Sdfr}; 4899336Sdfr 4909336Sdfrstatic short nfsv3err_commit[] = { 4919336Sdfr NFSERR_IO, 4929336Sdfr NFSERR_IO, 4939336Sdfr NFSERR_STALE, 4949336Sdfr NFSERR_BADHANDLE, 4959336Sdfr NFSERR_SERVERFAULT, 4969336Sdfr 0, 4979336Sdfr}; 4989336Sdfr 4999336Sdfrstatic short *nfsrv_v3errmap[] = { 5009336Sdfr nfsv3err_null, 5019336Sdfr nfsv3err_getattr, 5029336Sdfr nfsv3err_setattr, 5039336Sdfr nfsv3err_lookup, 5049336Sdfr nfsv3err_access, 5059336Sdfr nfsv3err_readlink, 5069336Sdfr nfsv3err_read, 5079336Sdfr nfsv3err_write, 5089336Sdfr nfsv3err_create, 5099336Sdfr nfsv3err_mkdir, 5109336Sdfr nfsv3err_symlink, 5119336Sdfr nfsv3err_mknod, 5129336Sdfr nfsv3err_remove, 5139336Sdfr nfsv3err_rmdir, 5149336Sdfr nfsv3err_rename, 5159336Sdfr nfsv3err_link, 5169336Sdfr nfsv3err_readdir, 5179336Sdfr nfsv3err_readdirplus, 5189336Sdfr nfsv3err_fsstat, 5199336Sdfr nfsv3err_fsinfo, 5209336Sdfr nfsv3err_pathconf, 5219336Sdfr nfsv3err_commit, 5229336Sdfr}; 5239336Sdfr 5241541Srgrimes/* 5251541Srgrimes * Called once to initialize data structures... 5261541Srgrimes */ 52783651Speterstatic int 52883700Speternfsrv_modevent(module_t mod, int type, void *data) 5291541Srgrimes{ 5301541Srgrimes 53183700Speter switch (type) { 53283700Speter case MOD_LOAD: 53389094Smsmith nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 53489094Smsmith nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 53589094Smsmith nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 53689094Smsmith nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 53789094Smsmith nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 53889094Smsmith nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 53989094Smsmith nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 54089094Smsmith nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 54189094Smsmith nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 54289094Smsmith nfsrv_nfs_true = txdr_unsigned(TRUE); 54389094Smsmith nfsrv_nfs_false = txdr_unsigned(FALSE); 54489094Smsmith nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 54589094Smsmith nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 54689094Smsmith if (nfsrv_ticks < 1) 54789094Smsmith nfsrv_ticks = 1; 54883651Speter 54983700Speter nfsrv_init(0); /* Init server data structures */ 55083700Speter nfsrv_initcache(); /* Init the server request cache */ 5511541Srgrimes 55283700Speter nfsrv_timer(0); 5531541Srgrimes 55483700Speter nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 55583700Speter sysent[SYS_nfssvc].sy_narg = 2; 55683700Speter nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 55783700Speter sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 55883700Speter break; 5592997Swollman 56083700Speter case MOD_UNLOAD: 56183700Speter 56283700Speter untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle); 56383700Speter sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 56483700Speter sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 56583700Speter break; 56683700Speter } 56783700Speter return 0; 5681541Srgrimes} 56983700Speterstatic moduledata_t nfsserver_mod = { 57083700Speter "nfsserver", 57183700Speter nfsrv_modevent, 57283700Speter NULL, 57383700Speter}; 57483700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 5751541Srgrimes 57683700Speter/* So that loader and kldload(2) can find us, wherever we are.. */ 57783700SpeterMODULE_VERSION(nfsserver, 1); 57838894Sbde 5791541Srgrimes/* 58027446Sdfr * Set up nameidata for a lookup() call and do it. 58127446Sdfr * 58227446Sdfr * If pubflag is set, this call is done for a lookup operation on the 58327446Sdfr * public filehandle. In that case we allow crossing mountpoints and 58427446Sdfr * absolute pathnames. However, the caller is expected to check that 58527446Sdfr * the lookup result is within the public fs, and deny access if 58627446Sdfr * it is not. 58748125Sjulian * 58848125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 58948125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 59048125Sjulian * error occurs but the parent was not requested. 59148125Sjulian * 59283651Speter * dirp may be set whether an error is returned or not, and must be 59348125Sjulian * released by the caller. 5941541Srgrimes */ 5951549Srgrimesint 59683651Speternfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 59783651Speter struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 59883651Speter caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag) 5991541Srgrimes{ 60083651Speter int i, rem; 60183651Speter struct mbuf *md; 60283651Speter char *fromcp, *tocp, *cp; 60327446Sdfr struct iovec aiov; 60427446Sdfr struct uio auio; 6051541Srgrimes struct vnode *dp; 60627446Sdfr int error, rdonly, linklen; 6071541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 6081541Srgrimes 60999797Sdillon *retdirp = NULL; 61092783Sjeff cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 61129653Sdyson 6121541Srgrimes /* 6131541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 6141541Srgrimes * and set the various ndp fields appropriately. 6151541Srgrimes */ 6161541Srgrimes fromcp = *dposp; 6171541Srgrimes tocp = cnp->cn_pnbuf; 6181541Srgrimes md = *mdp; 6191541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 6201541Srgrimes for (i = 0; i < len; i++) { 6211541Srgrimes while (rem == 0) { 6221541Srgrimes md = md->m_next; 6231541Srgrimes if (md == NULL) { 6241541Srgrimes error = EBADRPC; 6251541Srgrimes goto out; 6261541Srgrimes } 6271541Srgrimes fromcp = mtod(md, caddr_t); 6281541Srgrimes rem = md->m_len; 6291541Srgrimes } 63027446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 6319336Sdfr error = EACCES; 6321541Srgrimes goto out; 6331541Srgrimes } 6341541Srgrimes *tocp++ = *fromcp++; 6351541Srgrimes rem--; 6361541Srgrimes } 6371541Srgrimes *tocp = '\0'; 6381541Srgrimes *mdp = md; 6391541Srgrimes *dposp = fromcp; 6401541Srgrimes len = nfsm_rndup(len)-len; 6411541Srgrimes if (len > 0) { 6421541Srgrimes if (rem >= len) 6431541Srgrimes *dposp += len; 64427609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 6459336Sdfr goto out; 6461541Srgrimes } 64727446Sdfr 6481541Srgrimes /* 6491541Srgrimes * Extract and set starting directory. 6501541Srgrimes */ 65127446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 65283651Speter nam, &rdonly, pubflag); 65327446Sdfr if (error) 6541541Srgrimes goto out; 6551541Srgrimes if (dp->v_type != VDIR) { 65617761Sdyson vrele(dp); 6571541Srgrimes error = ENOTDIR; 6581541Srgrimes goto out; 6591541Srgrimes } 66027446Sdfr 66127446Sdfr if (rdonly) 66227446Sdfr cnp->cn_flags |= RDONLY; 66327446Sdfr 66448125Sjulian /* 66583651Speter * Set return directory. Reference to dp is implicitly transfered 66648125Sjulian * to the returned pointer 66748125Sjulian */ 66827609Sdfr *retdirp = dp; 66927609Sdfr 67027446Sdfr if (pubflag) { 67127446Sdfr /* 67227446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 67327446Sdfr * and the 'native path' indicator. 67427446Sdfr */ 67592783Sjeff cp = uma_zalloc(namei_zone, M_WAITOK); 67627446Sdfr fromcp = cnp->cn_pnbuf; 67727446Sdfr tocp = cp; 67827446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 67927446Sdfr switch ((unsigned char)*fromcp) { 68027446Sdfr case WEBNFS_NATIVE_CHAR: 68127446Sdfr /* 68227446Sdfr * 'Native' path for us is the same 68327446Sdfr * as a path according to the NFS spec, 68427446Sdfr * just skip the escape char. 68527446Sdfr */ 68627446Sdfr fromcp++; 68727446Sdfr break; 68827446Sdfr /* 68927446Sdfr * More may be added in the future, range 0x80-0xff 69027446Sdfr */ 69127446Sdfr default: 69227446Sdfr error = EIO; 69392783Sjeff uma_zfree(namei_zone, cp); 69427446Sdfr goto out; 69527446Sdfr } 69627446Sdfr } 69727446Sdfr /* 69827446Sdfr * Translate the '%' escapes, URL-style. 69927446Sdfr */ 70027446Sdfr while (*fromcp != '\0') { 70127446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 70227446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 70327446Sdfr fromcp++; 70427446Sdfr *tocp++ = HEXSTRTOI(fromcp); 70527446Sdfr fromcp += 2; 70627446Sdfr continue; 70727446Sdfr } else { 70827446Sdfr error = ENOENT; 70992783Sjeff uma_zfree(namei_zone, cp); 71027446Sdfr goto out; 71127446Sdfr } 71227446Sdfr } else 71327446Sdfr *tocp++ = *fromcp++; 71427446Sdfr } 71527446Sdfr *tocp = '\0'; 71692783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 71727446Sdfr cnp->cn_pnbuf = cp; 71827446Sdfr } 71927446Sdfr 72027446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 72127446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 72227446Sdfr 72327446Sdfr if (pubflag) { 72427446Sdfr ndp->ni_rootdir = rootvnode; 72527446Sdfr ndp->ni_loopcnt = 0; 72627446Sdfr if (cnp->cn_pnbuf[0] == '/') 72727446Sdfr dp = rootvnode; 72827446Sdfr } else { 72927609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 73027446Sdfr } 73127446Sdfr 73248125Sjulian /* 73348125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 73448125Sjulian * becuase lookup() will dereference ni_startdir. 73548125Sjulian */ 73648125Sjulian 73783366Sjulian cnp->cn_thread = td; 7389336Sdfr VREF(dp); 73948125Sjulian ndp->ni_startdir = dp; 74027446Sdfr 74148125Sjulian for (;;) { 74248125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 74348125Sjulian /* 74448125Sjulian * Call lookup() to do the real work. If an error occurs, 74548125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 74648125Sjulian * we do not have to dereference anything before returning. 74748125Sjulian * In either case ni_startdir will be dereferenced and NULLed 74848125Sjulian * out. 74948125Sjulian */ 75048125Sjulian error = lookup(ndp); 75148125Sjulian if (error) 75248125Sjulian break; 75348125Sjulian 75448125Sjulian /* 75583651Speter * Check for encountering a symbolic link. Trivial 75648125Sjulian * termination occurs if no symlink encountered. 75748125Sjulian * Note: zfree is safe because error is 0, so we will 75848125Sjulian * not zfree it again when we break. 75948125Sjulian */ 76048125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 76148125Sjulian nfsrv_object_create(ndp->ni_vp); 76248125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 76348125Sjulian cnp->cn_flags |= HASBUF; 76448125Sjulian else 76592783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 76648125Sjulian break; 76727446Sdfr } 76848125Sjulian 76948125Sjulian /* 77048125Sjulian * Validate symlink 77148125Sjulian */ 7721541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 77383366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 77427446Sdfr if (!pubflag) { 77527446Sdfr error = EINVAL; 77648125Sjulian goto badlink2; 77727446Sdfr } 77827446Sdfr 77927446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 78027446Sdfr error = ELOOP; 78148125Sjulian goto badlink2; 78227446Sdfr } 78327609Sdfr if (ndp->ni_pathlen > 1) 78492783Sjeff cp = uma_zalloc(namei_zone, M_WAITOK); 7851541Srgrimes else 78627446Sdfr cp = cnp->cn_pnbuf; 78727446Sdfr aiov.iov_base = cp; 78827446Sdfr aiov.iov_len = MAXPATHLEN; 78927446Sdfr auio.uio_iov = &aiov; 79027446Sdfr auio.uio_iovcnt = 1; 79127446Sdfr auio.uio_offset = 0; 79227446Sdfr auio.uio_rw = UIO_READ; 79327446Sdfr auio.uio_segflg = UIO_SYSSPACE; 79499797Sdillon auio.uio_td = NULL; 79527446Sdfr auio.uio_resid = MAXPATHLEN; 79627446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 79727446Sdfr if (error) { 79848125Sjulian badlink1: 79927446Sdfr if (ndp->ni_pathlen > 1) 80092783Sjeff uma_zfree(namei_zone, cp); 80148125Sjulian badlink2: 80248125Sjulian vrele(ndp->ni_dvp); 80348125Sjulian vput(ndp->ni_vp); 80427446Sdfr break; 80527446Sdfr } 80627446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 80727446Sdfr if (linklen == 0) { 80827446Sdfr error = ENOENT; 80948125Sjulian goto badlink1; 81027446Sdfr } 81127446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 81227446Sdfr error = ENAMETOOLONG; 81348125Sjulian goto badlink1; 81427446Sdfr } 81548125Sjulian 81648125Sjulian /* 81748125Sjulian * Adjust or replace path 81848125Sjulian */ 81927446Sdfr if (ndp->ni_pathlen > 1) { 82027446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 82192783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 82227446Sdfr cnp->cn_pnbuf = cp; 82327446Sdfr } else 82427446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 82527446Sdfr ndp->ni_pathlen += linklen; 82648125Sjulian 82727446Sdfr /* 82883651Speter * Cleanup refs for next loop and check if root directory 82983651Speter * should replace current directory. Normally ni_dvp 83048125Sjulian * becomes the new base directory and is cleaned up when 83148125Sjulian * we loop. Explicitly null pointers after invalidation 83248125Sjulian * to clarify operation. 83327446Sdfr */ 83448125Sjulian vput(ndp->ni_vp); 83548125Sjulian ndp->ni_vp = NULL; 83648125Sjulian 83727446Sdfr if (cnp->cn_pnbuf[0] == '/') { 83848125Sjulian vrele(ndp->ni_dvp); 83948125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 84048125Sjulian VREF(ndp->ni_dvp); 84127446Sdfr } 84248125Sjulian ndp->ni_startdir = ndp->ni_dvp; 84348125Sjulian ndp->ni_dvp = NULL; 8441541Srgrimes } 84548125Sjulian 84648125Sjulian /* 84748125Sjulian * nfs_namei() guarentees that fields will not contain garbage 84848125Sjulian * whether an error occurs or not. This allows the caller to track 84948125Sjulian * cleanup state trivially. 85048125Sjulian */ 8511541Srgrimesout: 85248125Sjulian if (error) { 85392783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 85448125Sjulian ndp->ni_vp = NULL; 85548125Sjulian ndp->ni_dvp = NULL; 85648125Sjulian ndp->ni_startdir = NULL; 85748125Sjulian cnp->cn_flags &= ~HASBUF; 85848125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 85948125Sjulian ndp->ni_dvp = NULL; 86048125Sjulian } 8611541Srgrimes return (error); 8621541Srgrimes} 8631541Srgrimes 8641541Srgrimes/* 8651541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 8661541Srgrimes * boundary and only trims off the back end 8671541Srgrimes */ 8681541Srgrimesvoid 86983651Speternfsm_adj(struct mbuf *mp, int len, int nul) 8701541Srgrimes{ 87183651Speter struct mbuf *m; 87283651Speter int count, i; 87383651Speter char *cp; 8741541Srgrimes 8751541Srgrimes /* 8761541Srgrimes * Trim from tail. Scan the mbuf chain, 8771541Srgrimes * calculating its length and finding the last mbuf. 8781541Srgrimes * If the adjustment only affects this mbuf, then just 8791541Srgrimes * adjust and return. Otherwise, rescan and truncate 8801541Srgrimes * after the remaining size. 8811541Srgrimes */ 8821541Srgrimes count = 0; 8831541Srgrimes m = mp; 8841541Srgrimes for (;;) { 8851541Srgrimes count += m->m_len; 88699797Sdillon if (m->m_next == NULL) 8871541Srgrimes break; 8881541Srgrimes m = m->m_next; 8891541Srgrimes } 8901541Srgrimes if (m->m_len > len) { 8911541Srgrimes m->m_len -= len; 8921541Srgrimes if (nul > 0) { 8931541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 8941541Srgrimes for (i = 0; i < nul; i++) 8951541Srgrimes *cp++ = '\0'; 8961541Srgrimes } 8971541Srgrimes return; 8981541Srgrimes } 8991541Srgrimes count -= len; 9001541Srgrimes if (count < 0) 9011541Srgrimes count = 0; 9021541Srgrimes /* 9031541Srgrimes * Correct length for chain is "count". 9041541Srgrimes * Find the mbuf with last data, adjust its length, 9051541Srgrimes * and toss data from remaining mbufs on chain. 9061541Srgrimes */ 9071541Srgrimes for (m = mp; m; m = m->m_next) { 9081541Srgrimes if (m->m_len >= count) { 9091541Srgrimes m->m_len = count; 9101541Srgrimes if (nul > 0) { 9111541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9121541Srgrimes for (i = 0; i < nul; i++) 9131541Srgrimes *cp++ = '\0'; 9141541Srgrimes } 9151541Srgrimes break; 9161541Srgrimes } 9171541Srgrimes count -= m->m_len; 9181541Srgrimes } 9193305Sphk for (m = m->m_next;m;m = m->m_next) 9201541Srgrimes m->m_len = 0; 9211541Srgrimes} 9221541Srgrimes 9231541Srgrimes/* 9249336Sdfr * Make these functions instead of macros, so that the kernel text size 9259336Sdfr * doesn't get too big... 9269336Sdfr */ 9279336Sdfrvoid 92883651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 92983651Speter struct vattr *before_vap, int after_ret, struct vattr *after_vap, 93083651Speter struct mbuf **mbp, char **bposp) 9319336Sdfr{ 93283651Speter struct mbuf *mb = *mbp; 93383651Speter char *bpos = *bposp; 93483651Speter u_int32_t *tl; 9359336Sdfr 9369336Sdfr if (before_ret) { 93784002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 93889094Smsmith *tl = nfsrv_nfs_false; 9399336Sdfr } else { 94084002Speter tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 94189094Smsmith *tl++ = nfsrv_nfs_true; 94247751Speter txdr_hyper(before_vap->va_size, tl); 9439336Sdfr tl += 2; 9449336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 9459336Sdfr tl += 2; 9469336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 9479336Sdfr } 9489336Sdfr *bposp = bpos; 9499336Sdfr *mbp = mb; 9509336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 9519336Sdfr} 9529336Sdfr 9539336Sdfrvoid 95483651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 95583651Speter struct vattr *after_vap, struct mbuf **mbp, char **bposp) 9569336Sdfr{ 95783651Speter struct mbuf *mb = *mbp; 95883651Speter char *bpos = *bposp; 95983651Speter u_int32_t *tl; 96083651Speter struct nfs_fattr *fp; 9619336Sdfr 9629336Sdfr if (after_ret) { 96384002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 96489094Smsmith *tl = nfsrv_nfs_false; 9659336Sdfr } else { 96684002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 96789094Smsmith *tl++ = nfsrv_nfs_true; 9689336Sdfr fp = (struct nfs_fattr *)tl; 9699336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 9709336Sdfr } 9719336Sdfr *mbp = mb; 9729336Sdfr *bposp = bpos; 9739336Sdfr} 9749336Sdfr 9759336Sdfrvoid 97683651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 97783651Speter struct nfs_fattr *fp) 9789336Sdfr{ 9799336Sdfr 9809336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 9819336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 9829336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 9839336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 9849336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 9859336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 98647751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 98747751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 98847028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 98947028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 9909336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 9919336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 9929336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 9939336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 9949336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 9959336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 9969336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 9979336Sdfr } else { 9989336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 9999336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 10009336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 10019336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 10029336Sdfr if (vap->va_type == VFIFO) 10039336Sdfr fp->fa2_rdev = 0xffffffff; 10049336Sdfr else 10059336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 10069336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 10079336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 10089336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 10099336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 10109336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 10119336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 10129336Sdfr } 10139336Sdfr} 10149336Sdfr 10159336Sdfr/* 10161541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10171541Srgrimes * - look up fsid in mount list (if not found ret error) 10181541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10191541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10201541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10211541Srgrimes */ 10221549Srgrimesint 102383651Speternfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 102483651Speter struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 102583651Speter int *rdonlyp, int pubflag) 10261541Srgrimes{ 102783366Sjulian struct thread *td = curthread; /* XXX */ 102883651Speter struct mount *mp; 102983651Speter int i; 10301541Srgrimes struct ucred *credanon; 10311541Srgrimes int error, exflags; 103236534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 103336534Speter struct sockaddr_int *saddr; 103436534Speter#endif 10351541Srgrimes 103699797Sdillon *vpp = NULL; 103727446Sdfr 103827446Sdfr if (nfs_ispublicfh(fhp)) { 103927446Sdfr if (!pubflag || !nfs_pub.np_valid) 104027446Sdfr return (ESTALE); 104127446Sdfr fhp = &nfs_pub.np_handle; 104227446Sdfr } 104327446Sdfr 104422521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 10453305Sphk if (!mp) 10461541Srgrimes return (ESTALE); 104751138Salfred error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 10483305Sphk if (error) 104983651Speter return (error); 105051138Salfred error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 105151138Salfred if (error) 10521541Srgrimes return (error); 105336534Speter#ifdef MNT_EXNORESPORT 105436534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 105536534Speter saddr = (struct sockaddr_in *)nam; 1056100134Salfred if ((saddr->sin_family == AF_INET || 1057100134Salfred saddr->sin_family == AF_INET6) && 1058100134Salfred /* same code for INET and INET6: sin*_port at same offet */ 105936534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 106036534Speter vput(*vpp); 106154485Sdillon *vpp = NULL; 106236534Speter return (NFSERR_AUTHERR | AUTH_TOOWEAK); 106336534Speter } 106436534Speter } 106536534Speter#endif 10661541Srgrimes /* 10671541Srgrimes * Check/setup credentials. 10681541Srgrimes */ 106983651Speter if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 10701541Srgrimes cred->cr_uid = credanon->cr_uid; 10711541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 10721541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 10733664Sphk cred->cr_ngroups = i; 10741541Srgrimes } 10751541Srgrimes if (exflags & MNT_EXRDONLY) 10761541Srgrimes *rdonlyp = 1; 10771541Srgrimes else 10781541Srgrimes *rdonlyp = 0; 10797969Sdyson 108017761Sdyson nfsrv_object_create(*vpp); 10817969Sdyson 10821541Srgrimes if (!lockflag) 108383366Sjulian VOP_UNLOCK(*vpp, 0, td); 10841541Srgrimes return (0); 10851541Srgrimes} 10861541Srgrimes 108727446Sdfr 108827446Sdfr/* 108927446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 109027446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 109127446Sdfr * transformed this to all zeroes in both cases, so check for it. 109227446Sdfr */ 109327446Sdfrint 109483651Speternfs_ispublicfh(fhandle_t *fhp) 109527446Sdfr{ 109627446Sdfr char *cp = (char *)fhp; 109727446Sdfr int i; 109827446Sdfr 109927446Sdfr for (i = 0; i < NFSX_V3FH; i++) 110027446Sdfr if (*cp++ != 0) 110127446Sdfr return (FALSE); 110227446Sdfr return (TRUE); 110327446Sdfr} 110483651Speter 11051541Srgrimes/* 11061541Srgrimes * This function compares two net addresses by family and returns TRUE 11071541Srgrimes * if they are the same host. 11081541Srgrimes * If there is any doubt, return FALSE. 11091541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11101541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11111541Srgrimes */ 11121549Srgrimesint 111383651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 11141541Srgrimes{ 111583651Speter struct sockaddr_in *inetaddr; 11161541Srgrimes 11171541Srgrimes switch (family) { 11181541Srgrimes case AF_INET: 111928270Swollman inetaddr = (struct sockaddr_in *)nam; 11201541Srgrimes if (inetaddr->sin_family == AF_INET && 11211541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11221541Srgrimes return (1); 11231541Srgrimes break; 1124100134Salfred#ifdef INET6 1125100134Salfred case AF_INET6: 1126100134Salfred { 1127100134Salfred register struct sockaddr_in6 *inet6addr1, *inet6addr2; 1128100134Salfred 1129100134Salfred inet6addr1 = (struct sockaddr_in6 *)nam; 1130100134Salfred inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 1131100134Salfred /* XXX - should test sin6_scope_id ? */ 1132100134Salfred if (inet6addr1->sin6_family == AF_INET6 && 1133100134Salfred IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 1134100134Salfred &inet6addr2->sin6_addr)) 1135100134Salfred return (1); 1136100134Salfred break; 1137100134Salfred } 1138100134Salfred#endif 11391541Srgrimes default: 11401541Srgrimes break; 11411541Srgrimes }; 11421541Srgrimes return (0); 11431541Srgrimes} 11445455Sdg 11459336Sdfr/* 11469336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 11479336Sdfr * numbers not specified for the associated procedure. 11489336Sdfr */ 11495455Sdgint 115083651Speternfsrv_errmap(struct nfsrv_descript *nd, int err) 11519336Sdfr{ 115283651Speter short *defaulterrp, *errp; 11539336Sdfr 11549336Sdfr if (nd->nd_flag & ND_NFSV3) { 11559336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 11569336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 11579336Sdfr while (*++errp) { 11589336Sdfr if (*errp == err) 11599336Sdfr return (err); 11609336Sdfr else if (*errp > err) 11619336Sdfr break; 11629336Sdfr } 11639336Sdfr return ((int)*defaulterrp); 11649336Sdfr } else 11659336Sdfr return (err & 0xffff); 11669336Sdfr } 11679336Sdfr if (err <= ELAST) 11689336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 11699336Sdfr return (NFSERR_IO); 11709336Sdfr} 11719336Sdfr 11729336Sdfrint 117383651Speternfsrv_object_create(struct vnode *vp) 117431886Sbde{ 11755455Sdg 117631886Sbde if (vp == NULL || vp->v_type != VREG) 117731886Sbde return (1); 117891406Sjhb return (vfs_object_create(vp, curthread, curthread->td_ucred)); 11795455Sdg} 118036503Speter 118136503Speter/* 118236503Speter * Sort the group list in increasing numerical order. 118336503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 118436503Speter * that used to be here.) 118536503Speter */ 118636503Spetervoid 118783651Speternfsrvw_sort(gid_t *list, int num) 118836503Speter{ 118983651Speter int i, j; 119036503Speter gid_t v; 119136503Speter 119236503Speter /* Insertion sort. */ 119336503Speter for (i = 1; i < num; i++) { 119436503Speter v = list[i]; 119536503Speter /* find correct slot for value v, moving others up */ 119636503Speter for (j = i; --j >= 0 && v < list[j];) 119736503Speter list[j + 1] = list[j]; 119836503Speter list[j + 1] = v; 119936503Speter } 120036503Speter} 120136503Speter 120236503Speter/* 120336503Speter * copy credentials making sure that the result can be compared with bcmp(). 120436503Speter */ 120536503Spetervoid 120683651Speternfsrv_setcred(struct ucred *incred, struct ucred *outcred) 120736503Speter{ 120883651Speter int i; 120936503Speter 121036503Speter bzero((caddr_t)outcred, sizeof (struct ucred)); 121136503Speter outcred->cr_ref = 1; 121236503Speter outcred->cr_uid = incred->cr_uid; 121336503Speter outcred->cr_ngroups = incred->cr_ngroups; 121436503Speter for (i = 0; i < incred->cr_ngroups; i++) 121536503Speter outcred->cr_groups[i] = incred->cr_groups[i]; 121636503Speter nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 121736503Speter} 121883651Speter 121983651Speter/* 122083651Speter * Helper functions for macros. 122183651Speter */ 122283651Speter 122383651Spetervoid 122488091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 122583651Speter{ 122688091Siedowse u_int32_t *tl; 122783651Speter 122883651Speter if (v3) { 122988091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 123088091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 123188091Siedowse bcopy(f, tl, NFSX_V3FH); 123283651Speter } else { 123388091Siedowse tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 123488091Siedowse bcopy(f, tl, NFSX_V2FH); 123583651Speter } 123683651Speter} 123783651Speter 123883651Spetervoid 123988091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 124083651Speter{ 124188091Siedowse u_int32_t *tl; 124284002Speter 124388091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 124489094Smsmith *tl++ = nfsrv_nfs_true; 124588091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 124688091Siedowse bcopy(f, tl, NFSX_V3FH); 124783651Speter} 124883651Speter 124983651Speterint 125088091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 125183651Speter{ 125288091Siedowse u_int32_t *tl; 125383651Speter 125488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 125588091Siedowse if (tl == NULL) 125684057Speter return EBADRPC; 125788091Siedowse *s = fxdr_unsigned(int32_t, *tl); 125883651Speter if (*s > m || *s <= 0) 125983651Speter return EBADRPC; 126083651Speter return 0; 126183651Speter} 126283651Speter 126383651Speterint 126488091Siedowsenfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos) 126583651Speter{ 126688091Siedowse u_int32_t *tl; 126783651Speter 126888091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 126988091Siedowse if (tl == NULL) 127084057Speter return EBADRPC; 127188091Siedowse *s = fxdr_unsigned(int32_t, *tl); 127283651Speter if (*s > NFS_MAXNAMLEN) 127383651Speter return NFSERR_NAMETOL; 127483651Speter if (*s <= 0) 127583651Speter return EBADRPC; 127683651Speter return 0; 127783651Speter} 127883651Speter 127983651Spetervoid 128083651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 128183651Speter char **bp, char **be, caddr_t bpos) 128283651Speter{ 128383651Speter struct mbuf *nmp; 128483651Speter 128583651Speter if (*bp >= *be) { 128683651Speter if (*mp == mb) 128783651Speter (*mp)->m_len += *bp - bpos; 128883651Speter MGET(nmp, M_TRYWAIT, MT_DATA); 128983651Speter MCLGET(nmp, M_TRYWAIT); 129083651Speter nmp->m_len = NFSMSIZ(nmp); 129183651Speter (*mp)->m_next = nmp; 129283651Speter *mp = nmp; 129383651Speter *bp = mtod(*mp, caddr_t); 129483651Speter *be = *bp + (*mp)->m_len; 129583651Speter } 129683651Speter *tl = (u_int32_t *)*bp; 129783651Speter} 129883651Speter 129983651Speterint 130088091Siedowsenfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 130188091Siedowse caddr_t *dpos) 130283651Speter{ 130388091Siedowse u_int32_t *tl; 130483651Speter int fhlen; 130583651Speter 130683651Speter if (nfsd->nd_flag & ND_NFSV3) { 130788091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 130888091Siedowse if (tl == NULL) 130984057Speter return EBADRPC; 131088091Siedowse fhlen = fxdr_unsigned(int, *tl); 131183651Speter if (fhlen != 0 && fhlen != NFSX_V3FH) 131283651Speter return EBADRPC; 131383651Speter } else { 131483651Speter fhlen = NFSX_V2FH; 131583651Speter } 131683651Speter if (fhlen != 0) { 131788091Siedowse tl = nfsm_dissect_xx(fhlen, md, dpos); 131888091Siedowse if (tl == NULL) 131984057Speter return EBADRPC; 132088091Siedowse bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 132183651Speter } else { 132283651Speter bzero((caddr_t)(f), NFSX_V3FH); 132383651Speter } 132483651Speter return 0; 132583651Speter} 132683651Speter 132783651Speterint 132888091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 132983651Speter{ 133088091Siedowse u_int32_t *tl; 133183651Speter 133288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 133388091Siedowse if (tl == NULL) 133484057Speter return EBADRPC; 133589094Smsmith if (*tl == nfsrv_nfs_true) { 133688091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 133788091Siedowse if (tl == NULL) 133884057Speter return EBADRPC; 133988091Siedowse (a)->va_mode = nfstov_mode(*tl); 134083651Speter } 134188091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 134288091Siedowse if (tl == NULL) 134384057Speter return EBADRPC; 134489094Smsmith if (*tl == nfsrv_nfs_true) { 134588091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 134688091Siedowse if (tl == NULL) 134784057Speter return EBADRPC; 134888091Siedowse (a)->va_uid = fxdr_unsigned(uid_t, *tl); 134983651Speter } 135088091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 135188091Siedowse if (tl == NULL) 135284057Speter return EBADRPC; 135389094Smsmith if (*tl == nfsrv_nfs_true) { 135488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 135588091Siedowse if (tl == NULL) 135684057Speter return EBADRPC; 135788091Siedowse (a)->va_gid = fxdr_unsigned(gid_t, *tl); 135883651Speter } 135988091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 136088091Siedowse if (tl == NULL) 136184057Speter return EBADRPC; 136289094Smsmith if (*tl == nfsrv_nfs_true) { 136388091Siedowse tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 136488091Siedowse if (tl == NULL) 136584057Speter return EBADRPC; 136688091Siedowse (a)->va_size = fxdr_hyper(tl); 136783651Speter } 136888091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 136988091Siedowse if (tl == NULL) 137084057Speter return EBADRPC; 137188091Siedowse switch (fxdr_unsigned(int, *tl)) { 137283651Speter case NFSV3SATTRTIME_TOCLIENT: 137388091Siedowse tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 137488091Siedowse if (tl == NULL) 137584057Speter return EBADRPC; 137688091Siedowse fxdr_nfsv3time(tl, &(a)->va_atime); 137783651Speter break; 137883651Speter case NFSV3SATTRTIME_TOSERVER: 137983651Speter getnanotime(&(a)->va_atime); 138083651Speter break; 138183651Speter } 138288091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 138388091Siedowse if (tl == NULL) 138484057Speter return EBADRPC; 138588091Siedowse switch (fxdr_unsigned(int, *tl)) { 138683651Speter case NFSV3SATTRTIME_TOCLIENT: 138788091Siedowse tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 138888091Siedowse if (tl == NULL) 138984057Speter return EBADRPC; 139088091Siedowse fxdr_nfsv3time(tl, &(a)->va_mtime); 139183651Speter break; 139283651Speter case NFSV3SATTRTIME_TOSERVER: 139383651Speter getnanotime(&(a)->va_mtime); 139483651Speter break; 139583651Speter } 139683651Speter return 0; 139783651Speter} 1398