nfs_srvsubs.c revision 84002
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 84002 2001-09-27 02:33:36Z peter $ 381541Srgrimes */ 391541Srgrimes 4083651Speter#include <sys/cdefs.h> 4183651Speter__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 84002 2001-09-27 02:33:36Z peter $"); 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 491541Srgrimes#include <sys/param.h> 5048274Speter#include <sys/systm.h> 5148274Speter#include <sys/kernel.h> 5260041Sphk#include <sys/bio.h> 5331886Sbde#include <sys/buf.h> 541541Srgrimes#include <sys/proc.h> 551541Srgrimes#include <sys/mount.h> 561541Srgrimes#include <sys/vnode.h> 571541Srgrimes#include <sys/namei.h> 581541Srgrimes#include <sys/mbuf.h> 591541Srgrimes#include <sys/socket.h> 601541Srgrimes#include <sys/stat.h> 619336Sdfr#include <sys/malloc.h> 6283700Speter#include <sys/module.h> 632997Swollman#include <sys/sysent.h> 642997Swollman#include <sys/syscall.h> 6583651Speter#include <sys/sysproto.h> 661541Srgrimes 673305Sphk#include <vm/vm.h> 6812662Sdg#include <vm/vm_object.h> 6912662Sdg#include <vm/vm_extern.h> 7032011Sbde#include <vm/vm_zone.h> 713305Sphk 721541Srgrimes#include <nfs/rpcv2.h> 739336Sdfr#include <nfs/nfsproto.h> 7483651Speter#include <nfsserver/nfs.h> 751541Srgrimes#include <nfs/xdr_subs.h> 7683651Speter#include <nfsserver/nfsm_subs.h> 771541Srgrimes 781541Srgrimes#include <netinet/in.h> 791541Srgrimes 801541Srgrimes/* 811541Srgrimes * Data items converted to xdr at startup, since they are constant 821541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 831541Srgrimes */ 8436541Speteru_int32_t nfs_xdrneg1; 8536541Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 8683651Speter rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 8783651Speteru_int32_t nfs_prog, nfs_true, nfs_false; 881541Srgrimes 891541Srgrimes/* And other global data */ 9083651Speterstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 9183651Speter NFNON, NFCHR, NFNON }; 9283651Speter#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 9383651Speter#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 9412911Sphk 959336Sdfrint nfs_ticks; 969336Sdfr 979759Sbdestruct nfssvc_sockhead nfssvc_sockhead; 989759Sbdeint nfssvc_sockhead_flag; 999759Sbdestruct nfsd_head nfsd_head; 1009759Sbdeint nfsd_head_flag; 1019759Sbde 10238894Sbdestatic int nfs_prev_nfssvc_sy_narg; 10338894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call; 10438894Sbde 1059336Sdfr/* 1069336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1079336Sdfr */ 1089336Sdfrint nfsv3_procid[NFS_NPROCS] = { 1099336Sdfr NFSPROC_NULL, 1109336Sdfr NFSPROC_GETATTR, 1119336Sdfr NFSPROC_SETATTR, 1129336Sdfr NFSPROC_NOOP, 1139336Sdfr NFSPROC_LOOKUP, 1149336Sdfr NFSPROC_READLINK, 1159336Sdfr NFSPROC_READ, 1169336Sdfr NFSPROC_NOOP, 1179336Sdfr NFSPROC_WRITE, 1189336Sdfr NFSPROC_CREATE, 1199336Sdfr NFSPROC_REMOVE, 1209336Sdfr NFSPROC_RENAME, 1219336Sdfr NFSPROC_LINK, 1229336Sdfr NFSPROC_SYMLINK, 1239336Sdfr NFSPROC_MKDIR, 1249336Sdfr NFSPROC_RMDIR, 1259336Sdfr NFSPROC_READDIR, 1269336Sdfr NFSPROC_FSSTAT, 1279336Sdfr NFSPROC_NOOP, 1289336Sdfr NFSPROC_NOOP, 1299336Sdfr NFSPROC_NOOP, 1309336Sdfr NFSPROC_NOOP, 1319336Sdfr NFSPROC_NOOP, 1329336Sdfr}; 1339336Sdfr 1349336Sdfr/* 1359336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1369336Sdfr */ 13783651Speterint nfsrvv2_procid[NFS_NPROCS] = { 1389336Sdfr NFSV2PROC_NULL, 1399336Sdfr NFSV2PROC_GETATTR, 1409336Sdfr NFSV2PROC_SETATTR, 1419336Sdfr NFSV2PROC_LOOKUP, 1429336Sdfr NFSV2PROC_NOOP, 1439336Sdfr NFSV2PROC_READLINK, 1449336Sdfr NFSV2PROC_READ, 1459336Sdfr NFSV2PROC_WRITE, 1469336Sdfr NFSV2PROC_CREATE, 1479336Sdfr NFSV2PROC_MKDIR, 1489336Sdfr NFSV2PROC_SYMLINK, 1499336Sdfr NFSV2PROC_CREATE, 1509336Sdfr NFSV2PROC_REMOVE, 1519336Sdfr NFSV2PROC_RMDIR, 1529336Sdfr NFSV2PROC_RENAME, 1539336Sdfr NFSV2PROC_LINK, 1549336Sdfr NFSV2PROC_READDIR, 1559336Sdfr NFSV2PROC_NOOP, 1569336Sdfr NFSV2PROC_STATFS, 1579336Sdfr NFSV2PROC_NOOP, 1589336Sdfr NFSV2PROC_NOOP, 1599336Sdfr NFSV2PROC_NOOP, 1609336Sdfr NFSV2PROC_NOOP, 1619336Sdfr}; 1629336Sdfr 1639336Sdfr/* 1649336Sdfr * Maps errno values to nfs error numbers. 1659336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1669336Sdfr * RFC 1094. 1679336Sdfr */ 1689336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1699336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1709336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1719336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1729336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 1739336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1749336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 1759336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1769336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1779336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 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_NAMETOL, NFSERR_IO, NFSERR_IO, 1829336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 1839336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1849336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 18541796Sdt NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 18641796Sdt NFSERR_IO /* << Last is 86 */ 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: 53083700Speter rpc_vers = txdr_unsigned(RPC_VER2); 53183700Speter rpc_call = txdr_unsigned(RPC_CALL); 53283700Speter rpc_reply = txdr_unsigned(RPC_REPLY); 53383700Speter rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 53483700Speter rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 53583700Speter rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 53683700Speter rpc_autherr = txdr_unsigned(RPC_AUTHERR); 53783700Speter rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 53883700Speter nfs_prog = txdr_unsigned(NFS_PROG); 53983700Speter nfs_true = txdr_unsigned(TRUE); 54083700Speter nfs_false = txdr_unsigned(FALSE); 54183700Speter nfs_xdrneg1 = txdr_unsigned(-1); 54283700Speter nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 54383700Speter if (nfs_ticks < 1) 54483700Speter nfs_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 6069336Sdfr *retdirp = (struct vnode *)0; 60729653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 60829653Sdyson 6091541Srgrimes /* 6101541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 6111541Srgrimes * and set the various ndp fields appropriately. 6121541Srgrimes */ 6131541Srgrimes fromcp = *dposp; 6141541Srgrimes tocp = cnp->cn_pnbuf; 6151541Srgrimes md = *mdp; 6161541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 6171541Srgrimes for (i = 0; i < len; i++) { 6181541Srgrimes while (rem == 0) { 6191541Srgrimes md = md->m_next; 6201541Srgrimes if (md == NULL) { 6211541Srgrimes error = EBADRPC; 6221541Srgrimes goto out; 6231541Srgrimes } 6241541Srgrimes fromcp = mtod(md, caddr_t); 6251541Srgrimes rem = md->m_len; 6261541Srgrimes } 62727446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 6289336Sdfr error = EACCES; 6291541Srgrimes goto out; 6301541Srgrimes } 6311541Srgrimes *tocp++ = *fromcp++; 6321541Srgrimes rem--; 6331541Srgrimes } 6341541Srgrimes *tocp = '\0'; 6351541Srgrimes *mdp = md; 6361541Srgrimes *dposp = fromcp; 6371541Srgrimes len = nfsm_rndup(len)-len; 6381541Srgrimes if (len > 0) { 6391541Srgrimes if (rem >= len) 6401541Srgrimes *dposp += len; 64127609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 6429336Sdfr goto out; 6431541Srgrimes } 64427446Sdfr 6451541Srgrimes /* 6461541Srgrimes * Extract and set starting directory. 6471541Srgrimes */ 64827446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 64983651Speter nam, &rdonly, pubflag); 65027446Sdfr if (error) 6511541Srgrimes goto out; 6521541Srgrimes if (dp->v_type != VDIR) { 65317761Sdyson vrele(dp); 6541541Srgrimes error = ENOTDIR; 6551541Srgrimes goto out; 6561541Srgrimes } 65727446Sdfr 65827446Sdfr if (rdonly) 65927446Sdfr cnp->cn_flags |= RDONLY; 66027446Sdfr 66148125Sjulian /* 66283651Speter * Set return directory. Reference to dp is implicitly transfered 66348125Sjulian * to the returned pointer 66448125Sjulian */ 66527609Sdfr *retdirp = dp; 66627609Sdfr 66727446Sdfr if (pubflag) { 66827446Sdfr /* 66927446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 67027446Sdfr * and the 'native path' indicator. 67127446Sdfr */ 67229653Sdyson cp = zalloc(namei_zone); 67327446Sdfr fromcp = cnp->cn_pnbuf; 67427446Sdfr tocp = cp; 67527446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 67627446Sdfr switch ((unsigned char)*fromcp) { 67727446Sdfr case WEBNFS_NATIVE_CHAR: 67827446Sdfr /* 67927446Sdfr * 'Native' path for us is the same 68027446Sdfr * as a path according to the NFS spec, 68127446Sdfr * just skip the escape char. 68227446Sdfr */ 68327446Sdfr fromcp++; 68427446Sdfr break; 68527446Sdfr /* 68627446Sdfr * More may be added in the future, range 0x80-0xff 68727446Sdfr */ 68827446Sdfr default: 68927446Sdfr error = EIO; 69029653Sdyson zfree(namei_zone, cp); 69127446Sdfr goto out; 69227446Sdfr } 69327446Sdfr } 69427446Sdfr /* 69527446Sdfr * Translate the '%' escapes, URL-style. 69627446Sdfr */ 69727446Sdfr while (*fromcp != '\0') { 69827446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 69927446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 70027446Sdfr fromcp++; 70127446Sdfr *tocp++ = HEXSTRTOI(fromcp); 70227446Sdfr fromcp += 2; 70327446Sdfr continue; 70427446Sdfr } else { 70527446Sdfr error = ENOENT; 70629653Sdyson zfree(namei_zone, cp); 70727446Sdfr goto out; 70827446Sdfr } 70927446Sdfr } else 71027446Sdfr *tocp++ = *fromcp++; 71127446Sdfr } 71227446Sdfr *tocp = '\0'; 71329653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 71427446Sdfr cnp->cn_pnbuf = cp; 71527446Sdfr } 71627446Sdfr 71727446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 71827446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 71927446Sdfr 72027446Sdfr if (pubflag) { 72127446Sdfr ndp->ni_rootdir = rootvnode; 72227446Sdfr ndp->ni_loopcnt = 0; 72327446Sdfr if (cnp->cn_pnbuf[0] == '/') 72427446Sdfr dp = rootvnode; 72527446Sdfr } else { 72627609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 72727446Sdfr } 72827446Sdfr 72948125Sjulian /* 73048125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 73148125Sjulian * becuase lookup() will dereference ni_startdir. 73248125Sjulian */ 73348125Sjulian 73483366Sjulian cnp->cn_thread = td; 7359336Sdfr VREF(dp); 73648125Sjulian ndp->ni_startdir = dp; 73727446Sdfr 73848125Sjulian for (;;) { 73948125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 74048125Sjulian /* 74148125Sjulian * Call lookup() to do the real work. If an error occurs, 74248125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 74348125Sjulian * we do not have to dereference anything before returning. 74448125Sjulian * In either case ni_startdir will be dereferenced and NULLed 74548125Sjulian * out. 74648125Sjulian */ 74748125Sjulian error = lookup(ndp); 74848125Sjulian if (error) 74948125Sjulian break; 75048125Sjulian 75148125Sjulian /* 75283651Speter * Check for encountering a symbolic link. Trivial 75348125Sjulian * termination occurs if no symlink encountered. 75448125Sjulian * Note: zfree is safe because error is 0, so we will 75548125Sjulian * not zfree it again when we break. 75648125Sjulian */ 75748125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 75848125Sjulian nfsrv_object_create(ndp->ni_vp); 75948125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 76048125Sjulian cnp->cn_flags |= HASBUF; 76148125Sjulian else 76248125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 76348125Sjulian break; 76427446Sdfr } 76548125Sjulian 76648125Sjulian /* 76748125Sjulian * Validate symlink 76848125Sjulian */ 7691541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 77083366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 77127446Sdfr if (!pubflag) { 77227446Sdfr error = EINVAL; 77348125Sjulian goto badlink2; 77427446Sdfr } 77527446Sdfr 77627446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 77727446Sdfr error = ELOOP; 77848125Sjulian goto badlink2; 77927446Sdfr } 78027609Sdfr if (ndp->ni_pathlen > 1) 78129653Sdyson cp = zalloc(namei_zone); 7821541Srgrimes else 78327446Sdfr cp = cnp->cn_pnbuf; 78427446Sdfr aiov.iov_base = cp; 78527446Sdfr aiov.iov_len = MAXPATHLEN; 78627446Sdfr auio.uio_iov = &aiov; 78727446Sdfr auio.uio_iovcnt = 1; 78827446Sdfr auio.uio_offset = 0; 78927446Sdfr auio.uio_rw = UIO_READ; 79027446Sdfr auio.uio_segflg = UIO_SYSSPACE; 79183366Sjulian auio.uio_td = (struct thread *)0; 79227446Sdfr auio.uio_resid = MAXPATHLEN; 79327446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 79427446Sdfr if (error) { 79548125Sjulian badlink1: 79627446Sdfr if (ndp->ni_pathlen > 1) 79729653Sdyson zfree(namei_zone, cp); 79848125Sjulian badlink2: 79948125Sjulian vrele(ndp->ni_dvp); 80048125Sjulian vput(ndp->ni_vp); 80127446Sdfr break; 80227446Sdfr } 80327446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 80427446Sdfr if (linklen == 0) { 80527446Sdfr error = ENOENT; 80648125Sjulian goto badlink1; 80727446Sdfr } 80827446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 80927446Sdfr error = ENAMETOOLONG; 81048125Sjulian goto badlink1; 81127446Sdfr } 81248125Sjulian 81348125Sjulian /* 81448125Sjulian * Adjust or replace path 81548125Sjulian */ 81627446Sdfr if (ndp->ni_pathlen > 1) { 81727446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 81829653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 81927446Sdfr cnp->cn_pnbuf = cp; 82027446Sdfr } else 82127446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 82227446Sdfr ndp->ni_pathlen += linklen; 82348125Sjulian 82427446Sdfr /* 82583651Speter * Cleanup refs for next loop and check if root directory 82683651Speter * should replace current directory. Normally ni_dvp 82748125Sjulian * becomes the new base directory and is cleaned up when 82848125Sjulian * we loop. Explicitly null pointers after invalidation 82948125Sjulian * to clarify operation. 83027446Sdfr */ 83148125Sjulian vput(ndp->ni_vp); 83248125Sjulian ndp->ni_vp = NULL; 83348125Sjulian 83427446Sdfr if (cnp->cn_pnbuf[0] == '/') { 83548125Sjulian vrele(ndp->ni_dvp); 83648125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 83748125Sjulian VREF(ndp->ni_dvp); 83827446Sdfr } 83948125Sjulian ndp->ni_startdir = ndp->ni_dvp; 84048125Sjulian ndp->ni_dvp = NULL; 8411541Srgrimes } 84248125Sjulian 84348125Sjulian /* 84448125Sjulian * nfs_namei() guarentees that fields will not contain garbage 84548125Sjulian * whether an error occurs or not. This allows the caller to track 84648125Sjulian * cleanup state trivially. 84748125Sjulian */ 8481541Srgrimesout: 84948125Sjulian if (error) { 85048125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 85148125Sjulian ndp->ni_vp = NULL; 85248125Sjulian ndp->ni_dvp = NULL; 85348125Sjulian ndp->ni_startdir = NULL; 85448125Sjulian cnp->cn_flags &= ~HASBUF; 85548125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 85648125Sjulian ndp->ni_dvp = NULL; 85748125Sjulian } 8581541Srgrimes return (error); 8591541Srgrimes} 8601541Srgrimes 8611541Srgrimes/* 8621541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 8631541Srgrimes * boundary and only trims off the back end 8641541Srgrimes */ 8651541Srgrimesvoid 86683651Speternfsm_adj(struct mbuf *mp, int len, int nul) 8671541Srgrimes{ 86883651Speter struct mbuf *m; 86983651Speter int count, i; 87083651Speter char *cp; 8711541Srgrimes 8721541Srgrimes /* 8731541Srgrimes * Trim from tail. Scan the mbuf chain, 8741541Srgrimes * calculating its length and finding the last mbuf. 8751541Srgrimes * If the adjustment only affects this mbuf, then just 8761541Srgrimes * adjust and return. Otherwise, rescan and truncate 8771541Srgrimes * after the remaining size. 8781541Srgrimes */ 8791541Srgrimes count = 0; 8801541Srgrimes m = mp; 8811541Srgrimes for (;;) { 8821541Srgrimes count += m->m_len; 8831541Srgrimes if (m->m_next == (struct mbuf *)0) 8841541Srgrimes break; 8851541Srgrimes m = m->m_next; 8861541Srgrimes } 8871541Srgrimes if (m->m_len > len) { 8881541Srgrimes m->m_len -= len; 8891541Srgrimes if (nul > 0) { 8901541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 8911541Srgrimes for (i = 0; i < nul; i++) 8921541Srgrimes *cp++ = '\0'; 8931541Srgrimes } 8941541Srgrimes return; 8951541Srgrimes } 8961541Srgrimes count -= len; 8971541Srgrimes if (count < 0) 8981541Srgrimes count = 0; 8991541Srgrimes /* 9001541Srgrimes * Correct length for chain is "count". 9011541Srgrimes * Find the mbuf with last data, adjust its length, 9021541Srgrimes * and toss data from remaining mbufs on chain. 9031541Srgrimes */ 9041541Srgrimes for (m = mp; m; m = m->m_next) { 9051541Srgrimes if (m->m_len >= count) { 9061541Srgrimes m->m_len = count; 9071541Srgrimes if (nul > 0) { 9081541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9091541Srgrimes for (i = 0; i < nul; i++) 9101541Srgrimes *cp++ = '\0'; 9111541Srgrimes } 9121541Srgrimes break; 9131541Srgrimes } 9141541Srgrimes count -= m->m_len; 9151541Srgrimes } 9163305Sphk for (m = m->m_next;m;m = m->m_next) 9171541Srgrimes m->m_len = 0; 9181541Srgrimes} 9191541Srgrimes 9201541Srgrimes/* 9219336Sdfr * Make these functions instead of macros, so that the kernel text size 9229336Sdfr * doesn't get too big... 9239336Sdfr */ 9249336Sdfrvoid 92583651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 92683651Speter struct vattr *before_vap, int after_ret, struct vattr *after_vap, 92783651Speter struct mbuf **mbp, char **bposp) 9289336Sdfr{ 92983651Speter struct mbuf *mb = *mbp; 93083651Speter char *bpos = *bposp; 93183651Speter u_int32_t *tl; 9329336Sdfr 9339336Sdfr if (before_ret) { 93484002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 9359336Sdfr *tl = nfs_false; 9369336Sdfr } else { 93784002Speter tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 9389336Sdfr *tl++ = nfs_true; 93947751Speter txdr_hyper(before_vap->va_size, tl); 9409336Sdfr tl += 2; 9419336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 9429336Sdfr tl += 2; 9439336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 9449336Sdfr } 9459336Sdfr *bposp = bpos; 9469336Sdfr *mbp = mb; 9479336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 9489336Sdfr} 9499336Sdfr 9509336Sdfrvoid 95183651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 95283651Speter struct vattr *after_vap, struct mbuf **mbp, char **bposp) 9539336Sdfr{ 95483651Speter struct mbuf *mb = *mbp; 95583651Speter char *bpos = *bposp; 95683651Speter u_int32_t *tl; 95783651Speter struct nfs_fattr *fp; 9589336Sdfr 9599336Sdfr if (after_ret) { 96084002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 9619336Sdfr *tl = nfs_false; 9629336Sdfr } else { 96384002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 9649336Sdfr *tl++ = nfs_true; 9659336Sdfr fp = (struct nfs_fattr *)tl; 9669336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 9679336Sdfr } 9689336Sdfr *mbp = mb; 9699336Sdfr *bposp = bpos; 9709336Sdfr} 9719336Sdfr 9729336Sdfrvoid 97383651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 97483651Speter struct nfs_fattr *fp) 9759336Sdfr{ 9769336Sdfr 9779336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 9789336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 9799336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 9809336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 9819336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 9829336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 98347751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 98447751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 98547028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 98647028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 9879336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 9889336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 9899336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 9909336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 9919336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 9929336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 9939336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 9949336Sdfr } else { 9959336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 9969336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 9979336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 9989336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 9999336Sdfr if (vap->va_type == VFIFO) 10009336Sdfr fp->fa2_rdev = 0xffffffff; 10019336Sdfr else 10029336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 10039336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 10049336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 10059336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 10069336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 10079336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 10089336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 10099336Sdfr } 10109336Sdfr} 10119336Sdfr 10129336Sdfr/* 10131541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10141541Srgrimes * - look up fsid in mount list (if not found ret error) 10151541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10161541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10171541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10181541Srgrimes */ 10191549Srgrimesint 102083651Speternfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 102183651Speter struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 102283651Speter int *rdonlyp, int pubflag) 10231541Srgrimes{ 102483366Sjulian struct thread *td = curthread; /* XXX */ 102583651Speter struct mount *mp; 102683651Speter int i; 10271541Srgrimes struct ucred *credanon; 10281541Srgrimes int error, exflags; 102936534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 103036534Speter struct sockaddr_int *saddr; 103136534Speter#endif 10321541Srgrimes 10331541Srgrimes *vpp = (struct vnode *)0; 103427446Sdfr 103527446Sdfr if (nfs_ispublicfh(fhp)) { 103627446Sdfr if (!pubflag || !nfs_pub.np_valid) 103727446Sdfr return (ESTALE); 103827446Sdfr fhp = &nfs_pub.np_handle; 103927446Sdfr } 104027446Sdfr 104122521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 10423305Sphk if (!mp) 10431541Srgrimes return (ESTALE); 104451138Salfred error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 10453305Sphk if (error) 104683651Speter return (error); 104751138Salfred error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 104851138Salfred if (error) 10491541Srgrimes return (error); 105036534Speter#ifdef MNT_EXNORESPORT 105136534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 105236534Speter saddr = (struct sockaddr_in *)nam; 105336534Speter if (saddr->sin_family == AF_INET && 105436534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 105536534Speter vput(*vpp); 105654485Sdillon *vpp = NULL; 105736534Speter return (NFSERR_AUTHERR | AUTH_TOOWEAK); 105836534Speter } 105936534Speter } 106036534Speter#endif 10611541Srgrimes /* 10621541Srgrimes * Check/setup credentials. 10631541Srgrimes */ 106483651Speter if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 10651541Srgrimes cred->cr_uid = credanon->cr_uid; 10661541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 10671541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 10683664Sphk cred->cr_ngroups = i; 10691541Srgrimes } 10701541Srgrimes if (exflags & MNT_EXRDONLY) 10711541Srgrimes *rdonlyp = 1; 10721541Srgrimes else 10731541Srgrimes *rdonlyp = 0; 10747969Sdyson 107517761Sdyson nfsrv_object_create(*vpp); 10767969Sdyson 10771541Srgrimes if (!lockflag) 107883366Sjulian VOP_UNLOCK(*vpp, 0, td); 10791541Srgrimes return (0); 10801541Srgrimes} 10811541Srgrimes 108227446Sdfr 108327446Sdfr/* 108427446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 108527446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 108627446Sdfr * transformed this to all zeroes in both cases, so check for it. 108727446Sdfr */ 108827446Sdfrint 108983651Speternfs_ispublicfh(fhandle_t *fhp) 109027446Sdfr{ 109127446Sdfr char *cp = (char *)fhp; 109227446Sdfr int i; 109327446Sdfr 109427446Sdfr for (i = 0; i < NFSX_V3FH; i++) 109527446Sdfr if (*cp++ != 0) 109627446Sdfr return (FALSE); 109727446Sdfr return (TRUE); 109827446Sdfr} 109983651Speter 11001541Srgrimes/* 11011541Srgrimes * This function compares two net addresses by family and returns TRUE 11021541Srgrimes * if they are the same host. 11031541Srgrimes * If there is any doubt, return FALSE. 11041541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11051541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11061541Srgrimes */ 11071549Srgrimesint 110883651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 11091541Srgrimes{ 111083651Speter struct sockaddr_in *inetaddr; 11111541Srgrimes 11121541Srgrimes switch (family) { 11131541Srgrimes case AF_INET: 111428270Swollman inetaddr = (struct sockaddr_in *)nam; 11151541Srgrimes if (inetaddr->sin_family == AF_INET && 11161541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11171541Srgrimes return (1); 11181541Srgrimes break; 11191541Srgrimes default: 11201541Srgrimes break; 11211541Srgrimes }; 11221541Srgrimes return (0); 11231541Srgrimes} 11245455Sdg 11259336Sdfr/* 11269336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 11279336Sdfr * numbers not specified for the associated procedure. 11289336Sdfr */ 11295455Sdgint 113083651Speternfsrv_errmap(struct nfsrv_descript *nd, int err) 11319336Sdfr{ 113283651Speter short *defaulterrp, *errp; 11339336Sdfr 11349336Sdfr if (nd->nd_flag & ND_NFSV3) { 11359336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 11369336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 11379336Sdfr while (*++errp) { 11389336Sdfr if (*errp == err) 11399336Sdfr return (err); 11409336Sdfr else if (*errp > err) 11419336Sdfr break; 11429336Sdfr } 11439336Sdfr return ((int)*defaulterrp); 11449336Sdfr } else 11459336Sdfr return (err & 0xffff); 11469336Sdfr } 11479336Sdfr if (err <= ELAST) 11489336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 11499336Sdfr return (NFSERR_IO); 11509336Sdfr} 11519336Sdfr 11529336Sdfrint 115383651Speternfsrv_object_create(struct vnode *vp) 115431886Sbde{ 11555455Sdg 115631886Sbde if (vp == NULL || vp->v_type != VREG) 115731886Sbde return (1); 115883366Sjulian return (vfs_object_create(vp, curthread, 115983366Sjulian curthread ? curthread->td_proc->p_ucred : NULL)); 11605455Sdg} 116136503Speter 116236503Speter/* 116336503Speter * Sort the group list in increasing numerical order. 116436503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 116536503Speter * that used to be here.) 116636503Speter */ 116736503Spetervoid 116883651Speternfsrvw_sort(gid_t *list, int num) 116936503Speter{ 117083651Speter int i, j; 117136503Speter gid_t v; 117236503Speter 117336503Speter /* Insertion sort. */ 117436503Speter for (i = 1; i < num; i++) { 117536503Speter v = list[i]; 117636503Speter /* find correct slot for value v, moving others up */ 117736503Speter for (j = i; --j >= 0 && v < list[j];) 117836503Speter list[j + 1] = list[j]; 117936503Speter list[j + 1] = v; 118036503Speter } 118136503Speter} 118236503Speter 118336503Speter/* 118436503Speter * copy credentials making sure that the result can be compared with bcmp(). 118536503Speter */ 118636503Spetervoid 118783651Speternfsrv_setcred(struct ucred *incred, struct ucred *outcred) 118836503Speter{ 118983651Speter int i; 119036503Speter 119136503Speter bzero((caddr_t)outcred, sizeof (struct ucred)); 119236503Speter outcred->cr_ref = 1; 119336503Speter outcred->cr_uid = incred->cr_uid; 119436503Speter outcred->cr_ngroups = incred->cr_ngroups; 119536503Speter for (i = 0; i < incred->cr_ngroups; i++) 119636503Speter outcred->cr_groups[i] = incred->cr_groups[i]; 119736503Speter nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 119836503Speter} 119983651Speter 120083651Speter/* 120183651Speter * Helper functions for macros. 120283651Speter */ 120383651Speter 120483651Spetervoid 120583651Speternfsm_srvfhtom_xx(fhandle_t *f, int v3, 120683651Speter u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 120783651Speter{ 120883651Speter u_int32_t *cp; 120983651Speter 121083651Speter if (v3) { 121184002Speter *tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 121283651Speter *(*tl)++ = txdr_unsigned(NFSX_V3FH); 121383651Speter bcopy(f, (*tl), NFSX_V3FH); 121483651Speter } else { 121584002Speter cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 121683651Speter bcopy(f, cp, NFSX_V2FH); 121783651Speter } 121883651Speter} 121983651Speter 122083651Spetervoid 122183651Speternfsm_srvpostop_fh_xx(fhandle_t *f, 122283651Speter u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 122383651Speter{ 122484002Speter 122584002Speter *tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 122683651Speter *(*tl)++ = nfs_true; 122783651Speter *(*tl)++ = txdr_unsigned(NFSX_V3FH); 122883651Speter bcopy(f, (*tl), NFSX_V3FH); 122983651Speter} 123083651Speter 123183651Speterint 123283651Speternfsm_srvstrsiz_xx(int *s, int m, 123383651Speter u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 123483651Speter{ 123583651Speter int ret; 123683651Speter 123783651Speter ret = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 123883651Speter if (ret) 123983651Speter return ret; 124083651Speter *s = fxdr_unsigned(int32_t, **tl); 124183651Speter if (*s > m || *s <= 0) 124283651Speter return EBADRPC; 124383651Speter return 0; 124483651Speter} 124583651Speter 124683651Speterint 124783651Speternfsm_srvnamesiz_xx(int *s, 124883651Speter u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 124983651Speter{ 125083651Speter int ret; 125183651Speter 125283651Speter ret = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 125383651Speter if (ret) 125483651Speter return ret; 125583651Speter *s = fxdr_unsigned(int32_t, **tl); 125683651Speter if (*s > NFS_MAXNAMLEN) 125783651Speter return NFSERR_NAMETOL; 125883651Speter if (*s <= 0) 125983651Speter return EBADRPC; 126083651Speter return 0; 126183651Speter} 126283651Speter 126383651Spetervoid 126483651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 126583651Speter char **bp, char **be, caddr_t bpos) 126683651Speter{ 126783651Speter struct mbuf *nmp; 126883651Speter 126983651Speter if (*bp >= *be) { 127083651Speter if (*mp == mb) 127183651Speter (*mp)->m_len += *bp - bpos; 127283651Speter MGET(nmp, M_TRYWAIT, MT_DATA); 127383651Speter MCLGET(nmp, M_TRYWAIT); 127483651Speter nmp->m_len = NFSMSIZ(nmp); 127583651Speter (*mp)->m_next = nmp; 127683651Speter *mp = nmp; 127783651Speter *bp = mtod(*mp, caddr_t); 127883651Speter *be = *bp + (*mp)->m_len; 127983651Speter } 128083651Speter *tl = (u_int32_t *)*bp; 128183651Speter} 128283651Speter 128383651Speterint 128483651Speternfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, 128583651Speter u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 128683651Speter{ 128783651Speter int error; 128883651Speter int fhlen; 128983651Speter 129083651Speter if (nfsd->nd_flag & ND_NFSV3) { 129183651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 129283651Speter if (error) 129383651Speter return error; 129483651Speter fhlen = fxdr_unsigned(int, **tl); 129583651Speter if (fhlen != 0 && fhlen != NFSX_V3FH) 129683651Speter return EBADRPC; 129783651Speter } else { 129883651Speter fhlen = NFSX_V2FH; 129983651Speter } 130083651Speter if (fhlen != 0) { 130183651Speter error = nfsm_dissect_xx((void **)tl, fhlen, md, dpos); 130283651Speter if (error) 130383651Speter return error; 130483651Speter bcopy((caddr_t)*tl, (caddr_t)(f), fhlen); 130583651Speter } else { 130683651Speter bzero((caddr_t)(f), NFSX_V3FH); 130783651Speter } 130883651Speter return 0; 130983651Speter} 131083651Speter 131183651Speterint 131283651Speternfsm_srvsattr_xx(struct vattr *a, 131383651Speter u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 131483651Speter{ 131583651Speter int error = 0; 131683651Speter 131783651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 131883651Speter if (error) 131983651Speter goto bugout; 132083651Speter if (**tl == nfs_true) { 132183651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 132283651Speter if (error) 132383651Speter goto bugout; 132483651Speter (a)->va_mode = nfstov_mode(**tl); 132583651Speter } 132683651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 132783651Speter if (error) 132883651Speter goto bugout; 132983651Speter if (**tl == nfs_true) { 133083651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 133183651Speter if (error) 133283651Speter goto bugout; 133383651Speter (a)->va_uid = fxdr_unsigned(uid_t, **tl); 133483651Speter } 133583651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 133683651Speter if (error) 133783651Speter goto bugout; 133883651Speter if (**tl == nfs_true) { 133983651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 134083651Speter if (error) 134183651Speter goto bugout; 134283651Speter (a)->va_gid = fxdr_unsigned(gid_t, **tl); 134383651Speter } 134483651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 134583651Speter if (error) 134683651Speter goto bugout; 134783651Speter if (**tl == nfs_true) { 134883651Speter error = nfsm_dissect_xx((void **)tl, 2 * NFSX_UNSIGNED, 134983651Speter md, dpos); 135083651Speter if (error) 135183651Speter goto bugout; 135283651Speter (a)->va_size = fxdr_hyper(*tl); 135383651Speter } 135483651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 135583651Speter if (error) 135683651Speter goto bugout; 135783651Speter switch (fxdr_unsigned(int, **tl)) { 135883651Speter case NFSV3SATTRTIME_TOCLIENT: 135983651Speter error = nfsm_dissect_xx((void **)tl, 2 * NFSX_UNSIGNED, 136083651Speter md, dpos); 136183651Speter if (error) 136283651Speter goto bugout; 136383651Speter fxdr_nfsv3time(*tl, &(a)->va_atime); 136483651Speter break; 136583651Speter case NFSV3SATTRTIME_TOSERVER: 136683651Speter getnanotime(&(a)->va_atime); 136783651Speter break; 136883651Speter } 136983651Speter error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 137083651Speter if (error) 137183651Speter goto bugout; 137283651Speter switch (fxdr_unsigned(int, **tl)) { 137383651Speter case NFSV3SATTRTIME_TOCLIENT: 137483651Speter error = nfsm_dissect_xx((void **)tl, 2 * NFSX_UNSIGNED, 137583651Speter md, dpos); 137683651Speter if (error) 137783651Speter goto bugout; 137883651Speter fxdr_nfsv3time(*tl, &(a)->va_mtime); 137983651Speter break; 138083651Speter case NFSV3SATTRTIME_TOSERVER: 138183651Speter getnanotime(&(a)->va_mtime); 138283651Speter break; 138383651Speter } 138483651Speter return 0; 138583651Speter 138683651Speterbugout: 138783651Speter return error; 138883651Speter} 138983651Speter 139083651Spetervoid 139183651Speternfs_rephead_xx(int s, struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 139283651Speter int error, struct mbuf **mrq, struct mbuf **mb, 139383651Speter struct mbuf **mreq, struct mbuf **mrep, caddr_t *bpos) 139483651Speter{ 139583651Speter 139683651Speter nfs_rephead(s, nfsd, slp, error, mrq, mb, bpos); 139783651Speter if (*mrep != NULL) { 139883651Speter m_freem(*mrep); 139983651Speter *mrep = NULL; 140083651Speter } 140183651Speter *mreq = *mrq; 140283651Speter} 1403