nfs_srvsubs.c revision 89094
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 89094 2002-01-08 19:41:06Z msmith $ 381541Srgrimes */ 391541Srgrimes 4083651Speter#include <sys/cdefs.h> 4183651Speter__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 89094 2002-01-08 19:41:06Z msmith $"); 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 */ 8489094Smsmithu_int32_t nfsrv_nfs_xdrneg1; 8589094Smsmithu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply, 8689094Smsmith nfsrv_rpc_msgdenied, nfsrv_rpc_autherr, 8789094Smsmith nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted; 8889094Smsmithu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false; 891541Srgrimes 901541Srgrimes/* And other global data */ 9183651Speterstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 9283651Speter NFNON, NFCHR, NFNON }; 9383651Speter#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 9483651Speter#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 9512911Sphk 9689094Smsmithint nfsrv_ticks; 979336Sdfr 989759Sbdestruct nfssvc_sockhead nfssvc_sockhead; 999759Sbdeint nfssvc_sockhead_flag; 1009759Sbdestruct nfsd_head nfsd_head; 1019759Sbdeint nfsd_head_flag; 1029759Sbde 10338894Sbdestatic int nfs_prev_nfssvc_sy_narg; 10438894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call; 10538894Sbde 1069336Sdfr/* 1079336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1089336Sdfr */ 10989094Smsmithint nfsrv_nfsv3_procid[NFS_NPROCS] = { 1109336Sdfr NFSPROC_NULL, 1119336Sdfr NFSPROC_GETATTR, 1129336Sdfr NFSPROC_SETATTR, 1139336Sdfr NFSPROC_NOOP, 1149336Sdfr NFSPROC_LOOKUP, 1159336Sdfr NFSPROC_READLINK, 1169336Sdfr NFSPROC_READ, 1179336Sdfr NFSPROC_NOOP, 1189336Sdfr NFSPROC_WRITE, 1199336Sdfr NFSPROC_CREATE, 1209336Sdfr NFSPROC_REMOVE, 1219336Sdfr NFSPROC_RENAME, 1229336Sdfr NFSPROC_LINK, 1239336Sdfr NFSPROC_SYMLINK, 1249336Sdfr NFSPROC_MKDIR, 1259336Sdfr NFSPROC_RMDIR, 1269336Sdfr NFSPROC_READDIR, 1279336Sdfr NFSPROC_FSSTAT, 1289336Sdfr NFSPROC_NOOP, 1299336Sdfr NFSPROC_NOOP, 1309336Sdfr NFSPROC_NOOP, 1319336Sdfr NFSPROC_NOOP, 1329336Sdfr NFSPROC_NOOP, 1339336Sdfr}; 1349336Sdfr 1359336Sdfr/* 1369336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1379336Sdfr */ 13883651Speterint nfsrvv2_procid[NFS_NPROCS] = { 1399336Sdfr NFSV2PROC_NULL, 1409336Sdfr NFSV2PROC_GETATTR, 1419336Sdfr NFSV2PROC_SETATTR, 1429336Sdfr NFSV2PROC_LOOKUP, 1439336Sdfr NFSV2PROC_NOOP, 1449336Sdfr NFSV2PROC_READLINK, 1459336Sdfr NFSV2PROC_READ, 1469336Sdfr NFSV2PROC_WRITE, 1479336Sdfr NFSV2PROC_CREATE, 1489336Sdfr NFSV2PROC_MKDIR, 1499336Sdfr NFSV2PROC_SYMLINK, 1509336Sdfr NFSV2PROC_CREATE, 1519336Sdfr NFSV2PROC_REMOVE, 1529336Sdfr NFSV2PROC_RMDIR, 1539336Sdfr NFSV2PROC_RENAME, 1549336Sdfr NFSV2PROC_LINK, 1559336Sdfr NFSV2PROC_READDIR, 1569336Sdfr NFSV2PROC_NOOP, 1579336Sdfr NFSV2PROC_STATFS, 1589336Sdfr NFSV2PROC_NOOP, 1599336Sdfr NFSV2PROC_NOOP, 1609336Sdfr NFSV2PROC_NOOP, 1619336Sdfr NFSV2PROC_NOOP, 1629336Sdfr}; 1639336Sdfr 1649336Sdfr/* 1659336Sdfr * Maps errno values to nfs error numbers. 1669336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in 1679336Sdfr * RFC 1094. 1689336Sdfr */ 1699336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = { 1709336Sdfr NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1719336Sdfr NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1729336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 1739336Sdfr NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 1749336Sdfr NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1759336Sdfr NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 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_IO, NFSERR_IO, NFSERR_IO, 1829336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 1839336Sdfr NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 1849336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 1859336Sdfr NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 18641796Sdt NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 18741796Sdt NFSERR_IO /* << Last is 86 */ 1889336Sdfr}; 1899336Sdfr 1909336Sdfr/* 1919336Sdfr * Maps errno values to nfs error numbers. 1929336Sdfr * Although it is not obvious whether or not NFS clients really care if 1939336Sdfr * a returned error value is in the specified list for the procedure, the 1949336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 1959336Sdfr * X/Open XNFS document is the only specification that defines error values 1969336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 1979336Sdfr * so I have decided to not do this for Version 2. 1989336Sdfr * The first entry is the default error return and the rest are the valid 1999336Sdfr * errors for that RPC in increasing numeric order. 2009336Sdfr */ 2019336Sdfrstatic short nfsv3err_null[] = { 2029336Sdfr 0, 2039336Sdfr 0, 2049336Sdfr}; 2059336Sdfr 2069336Sdfrstatic short nfsv3err_getattr[] = { 2079336Sdfr NFSERR_IO, 2089336Sdfr NFSERR_IO, 2099336Sdfr NFSERR_STALE, 2109336Sdfr NFSERR_BADHANDLE, 2119336Sdfr NFSERR_SERVERFAULT, 2129336Sdfr 0, 2139336Sdfr}; 2149336Sdfr 2159336Sdfrstatic short nfsv3err_setattr[] = { 2169336Sdfr NFSERR_IO, 2179336Sdfr NFSERR_PERM, 2189336Sdfr NFSERR_IO, 2199336Sdfr NFSERR_ACCES, 2209336Sdfr NFSERR_INVAL, 2219336Sdfr NFSERR_NOSPC, 2229336Sdfr NFSERR_ROFS, 2239336Sdfr NFSERR_DQUOT, 2249336Sdfr NFSERR_STALE, 2259336Sdfr NFSERR_BADHANDLE, 2269336Sdfr NFSERR_NOT_SYNC, 2279336Sdfr NFSERR_SERVERFAULT, 2289336Sdfr 0, 2299336Sdfr}; 2309336Sdfr 2319336Sdfrstatic short nfsv3err_lookup[] = { 2329336Sdfr NFSERR_IO, 2339336Sdfr NFSERR_NOENT, 2349336Sdfr NFSERR_IO, 2359336Sdfr NFSERR_ACCES, 2369336Sdfr NFSERR_NOTDIR, 2379336Sdfr NFSERR_NAMETOL, 2389336Sdfr NFSERR_STALE, 2399336Sdfr NFSERR_BADHANDLE, 2409336Sdfr NFSERR_SERVERFAULT, 2419336Sdfr 0, 2429336Sdfr}; 2439336Sdfr 2449336Sdfrstatic short nfsv3err_access[] = { 2459336Sdfr NFSERR_IO, 2469336Sdfr NFSERR_IO, 2479336Sdfr NFSERR_STALE, 2489336Sdfr NFSERR_BADHANDLE, 2499336Sdfr NFSERR_SERVERFAULT, 2509336Sdfr 0, 2519336Sdfr}; 2529336Sdfr 2539336Sdfrstatic short nfsv3err_readlink[] = { 2549336Sdfr NFSERR_IO, 2559336Sdfr NFSERR_IO, 2569336Sdfr NFSERR_ACCES, 2579336Sdfr NFSERR_INVAL, 2589336Sdfr NFSERR_STALE, 2599336Sdfr NFSERR_BADHANDLE, 2609336Sdfr NFSERR_NOTSUPP, 2619336Sdfr NFSERR_SERVERFAULT, 2629336Sdfr 0, 2639336Sdfr}; 2649336Sdfr 2659336Sdfrstatic short nfsv3err_read[] = { 2669336Sdfr NFSERR_IO, 2679336Sdfr NFSERR_IO, 2689336Sdfr NFSERR_NXIO, 2699336Sdfr NFSERR_ACCES, 2709336Sdfr NFSERR_INVAL, 2719336Sdfr NFSERR_STALE, 2729336Sdfr NFSERR_BADHANDLE, 2739336Sdfr NFSERR_SERVERFAULT, 2749336Sdfr 0, 2759336Sdfr}; 2769336Sdfr 2779336Sdfrstatic short nfsv3err_write[] = { 2789336Sdfr NFSERR_IO, 2799336Sdfr NFSERR_IO, 2809336Sdfr NFSERR_ACCES, 2819336Sdfr NFSERR_INVAL, 2829336Sdfr NFSERR_FBIG, 2839336Sdfr NFSERR_NOSPC, 2849336Sdfr NFSERR_ROFS, 2859336Sdfr NFSERR_DQUOT, 2869336Sdfr NFSERR_STALE, 2879336Sdfr NFSERR_BADHANDLE, 2889336Sdfr NFSERR_SERVERFAULT, 2899336Sdfr 0, 2909336Sdfr}; 2919336Sdfr 2929336Sdfrstatic short nfsv3err_create[] = { 2939336Sdfr NFSERR_IO, 2949336Sdfr NFSERR_IO, 2959336Sdfr NFSERR_ACCES, 2969336Sdfr NFSERR_EXIST, 2979336Sdfr NFSERR_NOTDIR, 2989336Sdfr NFSERR_NOSPC, 2999336Sdfr NFSERR_ROFS, 3009336Sdfr NFSERR_NAMETOL, 3019336Sdfr NFSERR_DQUOT, 3029336Sdfr NFSERR_STALE, 3039336Sdfr NFSERR_BADHANDLE, 3049336Sdfr NFSERR_NOTSUPP, 3059336Sdfr NFSERR_SERVERFAULT, 3069336Sdfr 0, 3079336Sdfr}; 3089336Sdfr 3099336Sdfrstatic short nfsv3err_mkdir[] = { 3109336Sdfr NFSERR_IO, 3119336Sdfr NFSERR_IO, 3129336Sdfr NFSERR_ACCES, 3139336Sdfr NFSERR_EXIST, 3149336Sdfr NFSERR_NOTDIR, 3159336Sdfr NFSERR_NOSPC, 3169336Sdfr NFSERR_ROFS, 3179336Sdfr NFSERR_NAMETOL, 3189336Sdfr NFSERR_DQUOT, 3199336Sdfr NFSERR_STALE, 3209336Sdfr NFSERR_BADHANDLE, 3219336Sdfr NFSERR_NOTSUPP, 3229336Sdfr NFSERR_SERVERFAULT, 3239336Sdfr 0, 3249336Sdfr}; 3259336Sdfr 3269336Sdfrstatic short nfsv3err_symlink[] = { 3279336Sdfr NFSERR_IO, 3289336Sdfr NFSERR_IO, 3299336Sdfr NFSERR_ACCES, 3309336Sdfr NFSERR_EXIST, 3319336Sdfr NFSERR_NOTDIR, 3329336Sdfr NFSERR_NOSPC, 3339336Sdfr NFSERR_ROFS, 3349336Sdfr NFSERR_NAMETOL, 3359336Sdfr NFSERR_DQUOT, 3369336Sdfr NFSERR_STALE, 3379336Sdfr NFSERR_BADHANDLE, 3389336Sdfr NFSERR_NOTSUPP, 3399336Sdfr NFSERR_SERVERFAULT, 3409336Sdfr 0, 3419336Sdfr}; 3429336Sdfr 3439336Sdfrstatic short nfsv3err_mknod[] = { 3449336Sdfr NFSERR_IO, 3459336Sdfr NFSERR_IO, 3469336Sdfr NFSERR_ACCES, 3479336Sdfr NFSERR_EXIST, 3489336Sdfr NFSERR_NOTDIR, 3499336Sdfr NFSERR_NOSPC, 3509336Sdfr NFSERR_ROFS, 3519336Sdfr NFSERR_NAMETOL, 3529336Sdfr NFSERR_DQUOT, 3539336Sdfr NFSERR_STALE, 3549336Sdfr NFSERR_BADHANDLE, 3559336Sdfr NFSERR_NOTSUPP, 3569336Sdfr NFSERR_SERVERFAULT, 3579336Sdfr NFSERR_BADTYPE, 3589336Sdfr 0, 3599336Sdfr}; 3609336Sdfr 3619336Sdfrstatic short nfsv3err_remove[] = { 3629336Sdfr NFSERR_IO, 3639336Sdfr NFSERR_NOENT, 3649336Sdfr NFSERR_IO, 3659336Sdfr NFSERR_ACCES, 3669336Sdfr NFSERR_NOTDIR, 3679336Sdfr NFSERR_ROFS, 3689336Sdfr NFSERR_NAMETOL, 3699336Sdfr NFSERR_STALE, 3709336Sdfr NFSERR_BADHANDLE, 3719336Sdfr NFSERR_SERVERFAULT, 3729336Sdfr 0, 3739336Sdfr}; 3749336Sdfr 3759336Sdfrstatic short nfsv3err_rmdir[] = { 3769336Sdfr NFSERR_IO, 3779336Sdfr NFSERR_NOENT, 3789336Sdfr NFSERR_IO, 3799336Sdfr NFSERR_ACCES, 3809336Sdfr NFSERR_EXIST, 3819336Sdfr NFSERR_NOTDIR, 3829336Sdfr NFSERR_INVAL, 3839336Sdfr NFSERR_ROFS, 3849336Sdfr NFSERR_NAMETOL, 3859336Sdfr NFSERR_NOTEMPTY, 3869336Sdfr NFSERR_STALE, 3879336Sdfr NFSERR_BADHANDLE, 3889336Sdfr NFSERR_NOTSUPP, 3899336Sdfr NFSERR_SERVERFAULT, 3909336Sdfr 0, 3919336Sdfr}; 3929336Sdfr 3939336Sdfrstatic short nfsv3err_rename[] = { 3949336Sdfr NFSERR_IO, 3959336Sdfr NFSERR_NOENT, 3969336Sdfr NFSERR_IO, 3979336Sdfr NFSERR_ACCES, 3989336Sdfr NFSERR_EXIST, 3999336Sdfr NFSERR_XDEV, 4009336Sdfr NFSERR_NOTDIR, 4019336Sdfr NFSERR_ISDIR, 4029336Sdfr NFSERR_INVAL, 4039336Sdfr NFSERR_NOSPC, 4049336Sdfr NFSERR_ROFS, 4059336Sdfr NFSERR_MLINK, 4069336Sdfr NFSERR_NAMETOL, 4079336Sdfr NFSERR_NOTEMPTY, 4089336Sdfr NFSERR_DQUOT, 4099336Sdfr NFSERR_STALE, 4109336Sdfr NFSERR_BADHANDLE, 4119336Sdfr NFSERR_NOTSUPP, 4129336Sdfr NFSERR_SERVERFAULT, 4139336Sdfr 0, 4149336Sdfr}; 4159336Sdfr 4169336Sdfrstatic short nfsv3err_link[] = { 4179336Sdfr NFSERR_IO, 4189336Sdfr NFSERR_IO, 4199336Sdfr NFSERR_ACCES, 4209336Sdfr NFSERR_EXIST, 4219336Sdfr NFSERR_XDEV, 4229336Sdfr NFSERR_NOTDIR, 4239336Sdfr NFSERR_INVAL, 4249336Sdfr NFSERR_NOSPC, 4259336Sdfr NFSERR_ROFS, 4269336Sdfr NFSERR_MLINK, 4279336Sdfr NFSERR_NAMETOL, 4289336Sdfr NFSERR_DQUOT, 4299336Sdfr NFSERR_STALE, 4309336Sdfr NFSERR_BADHANDLE, 4319336Sdfr NFSERR_NOTSUPP, 4329336Sdfr NFSERR_SERVERFAULT, 4339336Sdfr 0, 4349336Sdfr}; 4359336Sdfr 4369336Sdfrstatic short nfsv3err_readdir[] = { 4379336Sdfr NFSERR_IO, 4389336Sdfr NFSERR_IO, 4399336Sdfr NFSERR_ACCES, 4409336Sdfr NFSERR_NOTDIR, 4419336Sdfr NFSERR_STALE, 4429336Sdfr NFSERR_BADHANDLE, 4439336Sdfr NFSERR_BAD_COOKIE, 4449336Sdfr NFSERR_TOOSMALL, 4459336Sdfr NFSERR_SERVERFAULT, 4469336Sdfr 0, 4479336Sdfr}; 4489336Sdfr 4499336Sdfrstatic short nfsv3err_readdirplus[] = { 4509336Sdfr NFSERR_IO, 4519336Sdfr NFSERR_IO, 4529336Sdfr NFSERR_ACCES, 4539336Sdfr NFSERR_NOTDIR, 4549336Sdfr NFSERR_STALE, 4559336Sdfr NFSERR_BADHANDLE, 4569336Sdfr NFSERR_BAD_COOKIE, 4579336Sdfr NFSERR_NOTSUPP, 4589336Sdfr NFSERR_TOOSMALL, 4599336Sdfr NFSERR_SERVERFAULT, 4609336Sdfr 0, 4619336Sdfr}; 4629336Sdfr 4639336Sdfrstatic short nfsv3err_fsstat[] = { 4649336Sdfr NFSERR_IO, 4659336Sdfr NFSERR_IO, 4669336Sdfr NFSERR_STALE, 4679336Sdfr NFSERR_BADHANDLE, 4689336Sdfr NFSERR_SERVERFAULT, 4699336Sdfr 0, 4709336Sdfr}; 4719336Sdfr 4729336Sdfrstatic short nfsv3err_fsinfo[] = { 4739336Sdfr NFSERR_STALE, 4749336Sdfr NFSERR_STALE, 4759336Sdfr NFSERR_BADHANDLE, 4769336Sdfr NFSERR_SERVERFAULT, 4779336Sdfr 0, 4789336Sdfr}; 4799336Sdfr 4809336Sdfrstatic short nfsv3err_pathconf[] = { 4819336Sdfr NFSERR_STALE, 4829336Sdfr NFSERR_STALE, 4839336Sdfr NFSERR_BADHANDLE, 4849336Sdfr NFSERR_SERVERFAULT, 4859336Sdfr 0, 4869336Sdfr}; 4879336Sdfr 4889336Sdfrstatic short nfsv3err_commit[] = { 4899336Sdfr NFSERR_IO, 4909336Sdfr NFSERR_IO, 4919336Sdfr NFSERR_STALE, 4929336Sdfr NFSERR_BADHANDLE, 4939336Sdfr NFSERR_SERVERFAULT, 4949336Sdfr 0, 4959336Sdfr}; 4969336Sdfr 4979336Sdfrstatic short *nfsrv_v3errmap[] = { 4989336Sdfr nfsv3err_null, 4999336Sdfr nfsv3err_getattr, 5009336Sdfr nfsv3err_setattr, 5019336Sdfr nfsv3err_lookup, 5029336Sdfr nfsv3err_access, 5039336Sdfr nfsv3err_readlink, 5049336Sdfr nfsv3err_read, 5059336Sdfr nfsv3err_write, 5069336Sdfr nfsv3err_create, 5079336Sdfr nfsv3err_mkdir, 5089336Sdfr nfsv3err_symlink, 5099336Sdfr nfsv3err_mknod, 5109336Sdfr nfsv3err_remove, 5119336Sdfr nfsv3err_rmdir, 5129336Sdfr nfsv3err_rename, 5139336Sdfr nfsv3err_link, 5149336Sdfr nfsv3err_readdir, 5159336Sdfr nfsv3err_readdirplus, 5169336Sdfr nfsv3err_fsstat, 5179336Sdfr nfsv3err_fsinfo, 5189336Sdfr nfsv3err_pathconf, 5199336Sdfr nfsv3err_commit, 5209336Sdfr}; 5219336Sdfr 5221541Srgrimes/* 5231541Srgrimes * Called once to initialize data structures... 5241541Srgrimes */ 52583651Speterstatic int 52683700Speternfsrv_modevent(module_t mod, int type, void *data) 5271541Srgrimes{ 5281541Srgrimes 52983700Speter switch (type) { 53083700Speter case MOD_LOAD: 53189094Smsmith nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 53289094Smsmith nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 53389094Smsmith nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 53489094Smsmith nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 53589094Smsmith nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 53689094Smsmith nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 53789094Smsmith nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 53889094Smsmith nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 53989094Smsmith nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 54089094Smsmith nfsrv_nfs_true = txdr_unsigned(TRUE); 54189094Smsmith nfsrv_nfs_false = txdr_unsigned(FALSE); 54289094Smsmith nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 54389094Smsmith nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 54489094Smsmith if (nfsrv_ticks < 1) 54589094Smsmith nfsrv_ticks = 1; 54683651Speter 54783700Speter nfsrv_init(0); /* Init server data structures */ 54883700Speter nfsrv_initcache(); /* Init the server request cache */ 5491541Srgrimes 55083700Speter nfsrv_timer(0); 5511541Srgrimes 55283700Speter nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 55383700Speter sysent[SYS_nfssvc].sy_narg = 2; 55483700Speter nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 55583700Speter sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 55683700Speter break; 5572997Swollman 55883700Speter case MOD_UNLOAD: 55983700Speter 56083700Speter untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle); 56183700Speter sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 56283700Speter sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 56383700Speter break; 56483700Speter } 56583700Speter return 0; 5661541Srgrimes} 56783700Speterstatic moduledata_t nfsserver_mod = { 56883700Speter "nfsserver", 56983700Speter nfsrv_modevent, 57083700Speter NULL, 57183700Speter}; 57283700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 5731541Srgrimes 57483700Speter/* So that loader and kldload(2) can find us, wherever we are.. */ 57583700SpeterMODULE_VERSION(nfsserver, 1); 57638894Sbde 5771541Srgrimes/* 57827446Sdfr * Set up nameidata for a lookup() call and do it. 57927446Sdfr * 58027446Sdfr * If pubflag is set, this call is done for a lookup operation on the 58127446Sdfr * public filehandle. In that case we allow crossing mountpoints and 58227446Sdfr * absolute pathnames. However, the caller is expected to check that 58327446Sdfr * the lookup result is within the public fs, and deny access if 58427446Sdfr * it is not. 58548125Sjulian * 58648125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 58748125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 58848125Sjulian * error occurs but the parent was not requested. 58948125Sjulian * 59083651Speter * dirp may be set whether an error is returned or not, and must be 59148125Sjulian * released by the caller. 5921541Srgrimes */ 5931549Srgrimesint 59483651Speternfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 59583651Speter struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 59683651Speter caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag) 5971541Srgrimes{ 59883651Speter int i, rem; 59983651Speter struct mbuf *md; 60083651Speter char *fromcp, *tocp, *cp; 60127446Sdfr struct iovec aiov; 60227446Sdfr struct uio auio; 6031541Srgrimes struct vnode *dp; 60427446Sdfr int error, rdonly, linklen; 6051541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 6061541Srgrimes 6079336Sdfr *retdirp = (struct vnode *)0; 60829653Sdyson cnp->cn_pnbuf = zalloc(namei_zone); 60929653Sdyson 6101541Srgrimes /* 6111541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 6121541Srgrimes * and set the various ndp fields appropriately. 6131541Srgrimes */ 6141541Srgrimes fromcp = *dposp; 6151541Srgrimes tocp = cnp->cn_pnbuf; 6161541Srgrimes md = *mdp; 6171541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 6181541Srgrimes for (i = 0; i < len; i++) { 6191541Srgrimes while (rem == 0) { 6201541Srgrimes md = md->m_next; 6211541Srgrimes if (md == NULL) { 6221541Srgrimes error = EBADRPC; 6231541Srgrimes goto out; 6241541Srgrimes } 6251541Srgrimes fromcp = mtod(md, caddr_t); 6261541Srgrimes rem = md->m_len; 6271541Srgrimes } 62827446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 6299336Sdfr error = EACCES; 6301541Srgrimes goto out; 6311541Srgrimes } 6321541Srgrimes *tocp++ = *fromcp++; 6331541Srgrimes rem--; 6341541Srgrimes } 6351541Srgrimes *tocp = '\0'; 6361541Srgrimes *mdp = md; 6371541Srgrimes *dposp = fromcp; 6381541Srgrimes len = nfsm_rndup(len)-len; 6391541Srgrimes if (len > 0) { 6401541Srgrimes if (rem >= len) 6411541Srgrimes *dposp += len; 64227609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 6439336Sdfr goto out; 6441541Srgrimes } 64527446Sdfr 6461541Srgrimes /* 6471541Srgrimes * Extract and set starting directory. 6481541Srgrimes */ 64927446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 65083651Speter nam, &rdonly, pubflag); 65127446Sdfr if (error) 6521541Srgrimes goto out; 6531541Srgrimes if (dp->v_type != VDIR) { 65417761Sdyson vrele(dp); 6551541Srgrimes error = ENOTDIR; 6561541Srgrimes goto out; 6571541Srgrimes } 65827446Sdfr 65927446Sdfr if (rdonly) 66027446Sdfr cnp->cn_flags |= RDONLY; 66127446Sdfr 66248125Sjulian /* 66383651Speter * Set return directory. Reference to dp is implicitly transfered 66448125Sjulian * to the returned pointer 66548125Sjulian */ 66627609Sdfr *retdirp = dp; 66727609Sdfr 66827446Sdfr if (pubflag) { 66927446Sdfr /* 67027446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 67127446Sdfr * and the 'native path' indicator. 67227446Sdfr */ 67329653Sdyson cp = zalloc(namei_zone); 67427446Sdfr fromcp = cnp->cn_pnbuf; 67527446Sdfr tocp = cp; 67627446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 67727446Sdfr switch ((unsigned char)*fromcp) { 67827446Sdfr case WEBNFS_NATIVE_CHAR: 67927446Sdfr /* 68027446Sdfr * 'Native' path for us is the same 68127446Sdfr * as a path according to the NFS spec, 68227446Sdfr * just skip the escape char. 68327446Sdfr */ 68427446Sdfr fromcp++; 68527446Sdfr break; 68627446Sdfr /* 68727446Sdfr * More may be added in the future, range 0x80-0xff 68827446Sdfr */ 68927446Sdfr default: 69027446Sdfr error = EIO; 69129653Sdyson zfree(namei_zone, cp); 69227446Sdfr goto out; 69327446Sdfr } 69427446Sdfr } 69527446Sdfr /* 69627446Sdfr * Translate the '%' escapes, URL-style. 69727446Sdfr */ 69827446Sdfr while (*fromcp != '\0') { 69927446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 70027446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 70127446Sdfr fromcp++; 70227446Sdfr *tocp++ = HEXSTRTOI(fromcp); 70327446Sdfr fromcp += 2; 70427446Sdfr continue; 70527446Sdfr } else { 70627446Sdfr error = ENOENT; 70729653Sdyson zfree(namei_zone, cp); 70827446Sdfr goto out; 70927446Sdfr } 71027446Sdfr } else 71127446Sdfr *tocp++ = *fromcp++; 71227446Sdfr } 71327446Sdfr *tocp = '\0'; 71429653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 71527446Sdfr cnp->cn_pnbuf = cp; 71627446Sdfr } 71727446Sdfr 71827446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 71927446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 72027446Sdfr 72127446Sdfr if (pubflag) { 72227446Sdfr ndp->ni_rootdir = rootvnode; 72327446Sdfr ndp->ni_loopcnt = 0; 72427446Sdfr if (cnp->cn_pnbuf[0] == '/') 72527446Sdfr dp = rootvnode; 72627446Sdfr } else { 72727609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 72827446Sdfr } 72927446Sdfr 73048125Sjulian /* 73148125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 73248125Sjulian * becuase lookup() will dereference ni_startdir. 73348125Sjulian */ 73448125Sjulian 73583366Sjulian cnp->cn_thread = td; 7369336Sdfr VREF(dp); 73748125Sjulian ndp->ni_startdir = dp; 73827446Sdfr 73948125Sjulian for (;;) { 74048125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 74148125Sjulian /* 74248125Sjulian * Call lookup() to do the real work. If an error occurs, 74348125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 74448125Sjulian * we do not have to dereference anything before returning. 74548125Sjulian * In either case ni_startdir will be dereferenced and NULLed 74648125Sjulian * out. 74748125Sjulian */ 74848125Sjulian error = lookup(ndp); 74948125Sjulian if (error) 75048125Sjulian break; 75148125Sjulian 75248125Sjulian /* 75383651Speter * Check for encountering a symbolic link. Trivial 75448125Sjulian * termination occurs if no symlink encountered. 75548125Sjulian * Note: zfree is safe because error is 0, so we will 75648125Sjulian * not zfree it again when we break. 75748125Sjulian */ 75848125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 75948125Sjulian nfsrv_object_create(ndp->ni_vp); 76048125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 76148125Sjulian cnp->cn_flags |= HASBUF; 76248125Sjulian else 76348125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 76448125Sjulian break; 76527446Sdfr } 76648125Sjulian 76748125Sjulian /* 76848125Sjulian * Validate symlink 76948125Sjulian */ 7701541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 77183366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 77227446Sdfr if (!pubflag) { 77327446Sdfr error = EINVAL; 77448125Sjulian goto badlink2; 77527446Sdfr } 77627446Sdfr 77727446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 77827446Sdfr error = ELOOP; 77948125Sjulian goto badlink2; 78027446Sdfr } 78127609Sdfr if (ndp->ni_pathlen > 1) 78229653Sdyson cp = zalloc(namei_zone); 7831541Srgrimes else 78427446Sdfr cp = cnp->cn_pnbuf; 78527446Sdfr aiov.iov_base = cp; 78627446Sdfr aiov.iov_len = MAXPATHLEN; 78727446Sdfr auio.uio_iov = &aiov; 78827446Sdfr auio.uio_iovcnt = 1; 78927446Sdfr auio.uio_offset = 0; 79027446Sdfr auio.uio_rw = UIO_READ; 79127446Sdfr auio.uio_segflg = UIO_SYSSPACE; 79283366Sjulian auio.uio_td = (struct thread *)0; 79327446Sdfr auio.uio_resid = MAXPATHLEN; 79427446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 79527446Sdfr if (error) { 79648125Sjulian badlink1: 79727446Sdfr if (ndp->ni_pathlen > 1) 79829653Sdyson zfree(namei_zone, cp); 79948125Sjulian badlink2: 80048125Sjulian vrele(ndp->ni_dvp); 80148125Sjulian vput(ndp->ni_vp); 80227446Sdfr break; 80327446Sdfr } 80427446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 80527446Sdfr if (linklen == 0) { 80627446Sdfr error = ENOENT; 80748125Sjulian goto badlink1; 80827446Sdfr } 80927446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 81027446Sdfr error = ENAMETOOLONG; 81148125Sjulian goto badlink1; 81227446Sdfr } 81348125Sjulian 81448125Sjulian /* 81548125Sjulian * Adjust or replace path 81648125Sjulian */ 81727446Sdfr if (ndp->ni_pathlen > 1) { 81827446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 81929653Sdyson zfree(namei_zone, cnp->cn_pnbuf); 82027446Sdfr cnp->cn_pnbuf = cp; 82127446Sdfr } else 82227446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 82327446Sdfr ndp->ni_pathlen += linklen; 82448125Sjulian 82527446Sdfr /* 82683651Speter * Cleanup refs for next loop and check if root directory 82783651Speter * should replace current directory. Normally ni_dvp 82848125Sjulian * becomes the new base directory and is cleaned up when 82948125Sjulian * we loop. Explicitly null pointers after invalidation 83048125Sjulian * to clarify operation. 83127446Sdfr */ 83248125Sjulian vput(ndp->ni_vp); 83348125Sjulian ndp->ni_vp = NULL; 83448125Sjulian 83527446Sdfr if (cnp->cn_pnbuf[0] == '/') { 83648125Sjulian vrele(ndp->ni_dvp); 83748125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 83848125Sjulian VREF(ndp->ni_dvp); 83927446Sdfr } 84048125Sjulian ndp->ni_startdir = ndp->ni_dvp; 84148125Sjulian ndp->ni_dvp = NULL; 8421541Srgrimes } 84348125Sjulian 84448125Sjulian /* 84548125Sjulian * nfs_namei() guarentees that fields will not contain garbage 84648125Sjulian * whether an error occurs or not. This allows the caller to track 84748125Sjulian * cleanup state trivially. 84848125Sjulian */ 8491541Srgrimesout: 85048125Sjulian if (error) { 85148125Sjulian zfree(namei_zone, cnp->cn_pnbuf); 85248125Sjulian ndp->ni_vp = NULL; 85348125Sjulian ndp->ni_dvp = NULL; 85448125Sjulian ndp->ni_startdir = NULL; 85548125Sjulian cnp->cn_flags &= ~HASBUF; 85648125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 85748125Sjulian ndp->ni_dvp = NULL; 85848125Sjulian } 8591541Srgrimes return (error); 8601541Srgrimes} 8611541Srgrimes 8621541Srgrimes/* 8631541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 8641541Srgrimes * boundary and only trims off the back end 8651541Srgrimes */ 8661541Srgrimesvoid 86783651Speternfsm_adj(struct mbuf *mp, int len, int nul) 8681541Srgrimes{ 86983651Speter struct mbuf *m; 87083651Speter int count, i; 87183651Speter char *cp; 8721541Srgrimes 8731541Srgrimes /* 8741541Srgrimes * Trim from tail. Scan the mbuf chain, 8751541Srgrimes * calculating its length and finding the last mbuf. 8761541Srgrimes * If the adjustment only affects this mbuf, then just 8771541Srgrimes * adjust and return. Otherwise, rescan and truncate 8781541Srgrimes * after the remaining size. 8791541Srgrimes */ 8801541Srgrimes count = 0; 8811541Srgrimes m = mp; 8821541Srgrimes for (;;) { 8831541Srgrimes count += m->m_len; 8841541Srgrimes if (m->m_next == (struct mbuf *)0) 8851541Srgrimes break; 8861541Srgrimes m = m->m_next; 8871541Srgrimes } 8881541Srgrimes if (m->m_len > len) { 8891541Srgrimes m->m_len -= len; 8901541Srgrimes if (nul > 0) { 8911541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 8921541Srgrimes for (i = 0; i < nul; i++) 8931541Srgrimes *cp++ = '\0'; 8941541Srgrimes } 8951541Srgrimes return; 8961541Srgrimes } 8971541Srgrimes count -= len; 8981541Srgrimes if (count < 0) 8991541Srgrimes count = 0; 9001541Srgrimes /* 9011541Srgrimes * Correct length for chain is "count". 9021541Srgrimes * Find the mbuf with last data, adjust its length, 9031541Srgrimes * and toss data from remaining mbufs on chain. 9041541Srgrimes */ 9051541Srgrimes for (m = mp; m; m = m->m_next) { 9061541Srgrimes if (m->m_len >= count) { 9071541Srgrimes m->m_len = count; 9081541Srgrimes if (nul > 0) { 9091541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9101541Srgrimes for (i = 0; i < nul; i++) 9111541Srgrimes *cp++ = '\0'; 9121541Srgrimes } 9131541Srgrimes break; 9141541Srgrimes } 9151541Srgrimes count -= m->m_len; 9161541Srgrimes } 9173305Sphk for (m = m->m_next;m;m = m->m_next) 9181541Srgrimes m->m_len = 0; 9191541Srgrimes} 9201541Srgrimes 9211541Srgrimes/* 9229336Sdfr * Make these functions instead of macros, so that the kernel text size 9239336Sdfr * doesn't get too big... 9249336Sdfr */ 9259336Sdfrvoid 92683651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 92783651Speter struct vattr *before_vap, int after_ret, struct vattr *after_vap, 92883651Speter struct mbuf **mbp, char **bposp) 9299336Sdfr{ 93083651Speter struct mbuf *mb = *mbp; 93183651Speter char *bpos = *bposp; 93283651Speter u_int32_t *tl; 9339336Sdfr 9349336Sdfr if (before_ret) { 93584002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 93689094Smsmith *tl = nfsrv_nfs_false; 9379336Sdfr } else { 93884002Speter tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 93989094Smsmith *tl++ = nfsrv_nfs_true; 94047751Speter txdr_hyper(before_vap->va_size, tl); 9419336Sdfr tl += 2; 9429336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 9439336Sdfr tl += 2; 9449336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 9459336Sdfr } 9469336Sdfr *bposp = bpos; 9479336Sdfr *mbp = mb; 9489336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 9499336Sdfr} 9509336Sdfr 9519336Sdfrvoid 95283651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 95383651Speter struct vattr *after_vap, struct mbuf **mbp, char **bposp) 9549336Sdfr{ 95583651Speter struct mbuf *mb = *mbp; 95683651Speter char *bpos = *bposp; 95783651Speter u_int32_t *tl; 95883651Speter struct nfs_fattr *fp; 9599336Sdfr 9609336Sdfr if (after_ret) { 96184002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 96289094Smsmith *tl = nfsrv_nfs_false; 9639336Sdfr } else { 96484002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 96589094Smsmith *tl++ = nfsrv_nfs_true; 9669336Sdfr fp = (struct nfs_fattr *)tl; 9679336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 9689336Sdfr } 9699336Sdfr *mbp = mb; 9709336Sdfr *bposp = bpos; 9719336Sdfr} 9729336Sdfr 9739336Sdfrvoid 97483651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 97583651Speter struct nfs_fattr *fp) 9769336Sdfr{ 9779336Sdfr 9789336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 9799336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 9809336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 9819336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 9829336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 9839336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 98447751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 98547751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 98647028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 98747028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 9889336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 9899336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 9909336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 9919336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 9929336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 9939336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 9949336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 9959336Sdfr } else { 9969336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 9979336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 9989336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 9999336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 10009336Sdfr if (vap->va_type == VFIFO) 10019336Sdfr fp->fa2_rdev = 0xffffffff; 10029336Sdfr else 10039336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 10049336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 10059336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 10069336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 10079336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 10089336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 10099336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 10109336Sdfr } 10119336Sdfr} 10129336Sdfr 10139336Sdfr/* 10141541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10151541Srgrimes * - look up fsid in mount list (if not found ret error) 10161541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10171541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10181541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10191541Srgrimes */ 10201549Srgrimesint 102183651Speternfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 102283651Speter struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 102383651Speter int *rdonlyp, int pubflag) 10241541Srgrimes{ 102583366Sjulian struct thread *td = curthread; /* XXX */ 102683651Speter struct mount *mp; 102783651Speter int i; 10281541Srgrimes struct ucred *credanon; 10291541Srgrimes int error, exflags; 103036534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 103136534Speter struct sockaddr_int *saddr; 103236534Speter#endif 10331541Srgrimes 10341541Srgrimes *vpp = (struct vnode *)0; 103527446Sdfr 103627446Sdfr if (nfs_ispublicfh(fhp)) { 103727446Sdfr if (!pubflag || !nfs_pub.np_valid) 103827446Sdfr return (ESTALE); 103927446Sdfr fhp = &nfs_pub.np_handle; 104027446Sdfr } 104127446Sdfr 104222521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 10433305Sphk if (!mp) 10441541Srgrimes return (ESTALE); 104551138Salfred error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 10463305Sphk if (error) 104783651Speter return (error); 104851138Salfred error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 104951138Salfred if (error) 10501541Srgrimes return (error); 105136534Speter#ifdef MNT_EXNORESPORT 105236534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 105336534Speter saddr = (struct sockaddr_in *)nam; 105436534Speter if (saddr->sin_family == AF_INET && 105536534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 105636534Speter vput(*vpp); 105754485Sdillon *vpp = NULL; 105836534Speter return (NFSERR_AUTHERR | AUTH_TOOWEAK); 105936534Speter } 106036534Speter } 106136534Speter#endif 10621541Srgrimes /* 10631541Srgrimes * Check/setup credentials. 10641541Srgrimes */ 106583651Speter if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 10661541Srgrimes cred->cr_uid = credanon->cr_uid; 10671541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 10681541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 10693664Sphk cred->cr_ngroups = i; 10701541Srgrimes } 10711541Srgrimes if (exflags & MNT_EXRDONLY) 10721541Srgrimes *rdonlyp = 1; 10731541Srgrimes else 10741541Srgrimes *rdonlyp = 0; 10757969Sdyson 107617761Sdyson nfsrv_object_create(*vpp); 10777969Sdyson 10781541Srgrimes if (!lockflag) 107983366Sjulian VOP_UNLOCK(*vpp, 0, td); 10801541Srgrimes return (0); 10811541Srgrimes} 10821541Srgrimes 108327446Sdfr 108427446Sdfr/* 108527446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 108627446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 108727446Sdfr * transformed this to all zeroes in both cases, so check for it. 108827446Sdfr */ 108927446Sdfrint 109083651Speternfs_ispublicfh(fhandle_t *fhp) 109127446Sdfr{ 109227446Sdfr char *cp = (char *)fhp; 109327446Sdfr int i; 109427446Sdfr 109527446Sdfr for (i = 0; i < NFSX_V3FH; i++) 109627446Sdfr if (*cp++ != 0) 109727446Sdfr return (FALSE); 109827446Sdfr return (TRUE); 109927446Sdfr} 110083651Speter 11011541Srgrimes/* 11021541Srgrimes * This function compares two net addresses by family and returns TRUE 11031541Srgrimes * if they are the same host. 11041541Srgrimes * If there is any doubt, return FALSE. 11051541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11061541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11071541Srgrimes */ 11081549Srgrimesint 110983651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 11101541Srgrimes{ 111183651Speter struct sockaddr_in *inetaddr; 11121541Srgrimes 11131541Srgrimes switch (family) { 11141541Srgrimes case AF_INET: 111528270Swollman inetaddr = (struct sockaddr_in *)nam; 11161541Srgrimes if (inetaddr->sin_family == AF_INET && 11171541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11181541Srgrimes return (1); 11191541Srgrimes break; 11201541Srgrimes default: 11211541Srgrimes break; 11221541Srgrimes }; 11231541Srgrimes return (0); 11241541Srgrimes} 11255455Sdg 11269336Sdfr/* 11279336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 11289336Sdfr * numbers not specified for the associated procedure. 11299336Sdfr */ 11305455Sdgint 113183651Speternfsrv_errmap(struct nfsrv_descript *nd, int err) 11329336Sdfr{ 113383651Speter short *defaulterrp, *errp; 11349336Sdfr 11359336Sdfr if (nd->nd_flag & ND_NFSV3) { 11369336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 11379336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 11389336Sdfr while (*++errp) { 11399336Sdfr if (*errp == err) 11409336Sdfr return (err); 11419336Sdfr else if (*errp > err) 11429336Sdfr break; 11439336Sdfr } 11449336Sdfr return ((int)*defaulterrp); 11459336Sdfr } else 11469336Sdfr return (err & 0xffff); 11479336Sdfr } 11489336Sdfr if (err <= ELAST) 11499336Sdfr return ((int)nfsrv_v2errmap[err - 1]); 11509336Sdfr return (NFSERR_IO); 11519336Sdfr} 11529336Sdfr 11539336Sdfrint 115483651Speternfsrv_object_create(struct vnode *vp) 115531886Sbde{ 11565455Sdg 115731886Sbde if (vp == NULL || vp->v_type != VREG) 115831886Sbde return (1); 115983366Sjulian return (vfs_object_create(vp, curthread, 116083366Sjulian curthread ? curthread->td_proc->p_ucred : NULL)); 11615455Sdg} 116236503Speter 116336503Speter/* 116436503Speter * Sort the group list in increasing numerical order. 116536503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 116636503Speter * that used to be here.) 116736503Speter */ 116836503Spetervoid 116983651Speternfsrvw_sort(gid_t *list, int num) 117036503Speter{ 117183651Speter int i, j; 117236503Speter gid_t v; 117336503Speter 117436503Speter /* Insertion sort. */ 117536503Speter for (i = 1; i < num; i++) { 117636503Speter v = list[i]; 117736503Speter /* find correct slot for value v, moving others up */ 117836503Speter for (j = i; --j >= 0 && v < list[j];) 117936503Speter list[j + 1] = list[j]; 118036503Speter list[j + 1] = v; 118136503Speter } 118236503Speter} 118336503Speter 118436503Speter/* 118536503Speter * copy credentials making sure that the result can be compared with bcmp(). 118636503Speter */ 118736503Spetervoid 118883651Speternfsrv_setcred(struct ucred *incred, struct ucred *outcred) 118936503Speter{ 119083651Speter int i; 119136503Speter 119236503Speter bzero((caddr_t)outcred, sizeof (struct ucred)); 119336503Speter outcred->cr_ref = 1; 119436503Speter outcred->cr_uid = incred->cr_uid; 119536503Speter outcred->cr_ngroups = incred->cr_ngroups; 119636503Speter for (i = 0; i < incred->cr_ngroups; i++) 119736503Speter outcred->cr_groups[i] = incred->cr_groups[i]; 119836503Speter nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 119936503Speter} 120083651Speter 120183651Speter/* 120283651Speter * Helper functions for macros. 120383651Speter */ 120483651Speter 120583651Spetervoid 120688091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 120783651Speter{ 120888091Siedowse u_int32_t *tl; 120983651Speter 121083651Speter if (v3) { 121188091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 121288091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 121388091Siedowse bcopy(f, tl, NFSX_V3FH); 121483651Speter } else { 121588091Siedowse tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 121688091Siedowse bcopy(f, tl, NFSX_V2FH); 121783651Speter } 121883651Speter} 121983651Speter 122083651Spetervoid 122188091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 122283651Speter{ 122388091Siedowse u_int32_t *tl; 122484002Speter 122588091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 122689094Smsmith *tl++ = nfsrv_nfs_true; 122788091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 122888091Siedowse bcopy(f, tl, NFSX_V3FH); 122983651Speter} 123083651Speter 123183651Speterint 123288091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 123383651Speter{ 123488091Siedowse u_int32_t *tl; 123583651Speter 123688091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 123788091Siedowse if (tl == NULL) 123884057Speter return EBADRPC; 123988091Siedowse *s = fxdr_unsigned(int32_t, *tl); 124083651Speter if (*s > m || *s <= 0) 124183651Speter return EBADRPC; 124283651Speter return 0; 124383651Speter} 124483651Speter 124583651Speterint 124688091Siedowsenfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos) 124783651Speter{ 124888091Siedowse u_int32_t *tl; 124983651Speter 125088091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 125188091Siedowse if (tl == NULL) 125284057Speter return EBADRPC; 125388091Siedowse *s = fxdr_unsigned(int32_t, *tl); 125483651Speter if (*s > NFS_MAXNAMLEN) 125583651Speter return NFSERR_NAMETOL; 125683651Speter if (*s <= 0) 125783651Speter return EBADRPC; 125883651Speter return 0; 125983651Speter} 126083651Speter 126183651Spetervoid 126283651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 126383651Speter char **bp, char **be, caddr_t bpos) 126483651Speter{ 126583651Speter struct mbuf *nmp; 126683651Speter 126783651Speter if (*bp >= *be) { 126883651Speter if (*mp == mb) 126983651Speter (*mp)->m_len += *bp - bpos; 127083651Speter MGET(nmp, M_TRYWAIT, MT_DATA); 127183651Speter MCLGET(nmp, M_TRYWAIT); 127283651Speter nmp->m_len = NFSMSIZ(nmp); 127383651Speter (*mp)->m_next = nmp; 127483651Speter *mp = nmp; 127583651Speter *bp = mtod(*mp, caddr_t); 127683651Speter *be = *bp + (*mp)->m_len; 127783651Speter } 127883651Speter *tl = (u_int32_t *)*bp; 127983651Speter} 128083651Speter 128183651Speterint 128288091Siedowsenfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 128388091Siedowse caddr_t *dpos) 128483651Speter{ 128588091Siedowse u_int32_t *tl; 128683651Speter int fhlen; 128783651Speter 128883651Speter if (nfsd->nd_flag & ND_NFSV3) { 128988091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 129088091Siedowse if (tl == NULL) 129184057Speter return EBADRPC; 129288091Siedowse fhlen = fxdr_unsigned(int, *tl); 129383651Speter if (fhlen != 0 && fhlen != NFSX_V3FH) 129483651Speter return EBADRPC; 129583651Speter } else { 129683651Speter fhlen = NFSX_V2FH; 129783651Speter } 129883651Speter if (fhlen != 0) { 129988091Siedowse tl = nfsm_dissect_xx(fhlen, md, dpos); 130088091Siedowse if (tl == NULL) 130184057Speter return EBADRPC; 130288091Siedowse bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 130383651Speter } else { 130483651Speter bzero((caddr_t)(f), NFSX_V3FH); 130583651Speter } 130683651Speter return 0; 130783651Speter} 130883651Speter 130983651Speterint 131088091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 131183651Speter{ 131288091Siedowse u_int32_t *tl; 131383651Speter 131488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 131588091Siedowse if (tl == NULL) 131684057Speter return EBADRPC; 131789094Smsmith if (*tl == nfsrv_nfs_true) { 131888091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 131988091Siedowse if (tl == NULL) 132084057Speter return EBADRPC; 132188091Siedowse (a)->va_mode = nfstov_mode(*tl); 132283651Speter } 132388091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 132488091Siedowse if (tl == NULL) 132584057Speter return EBADRPC; 132689094Smsmith if (*tl == nfsrv_nfs_true) { 132788091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 132888091Siedowse if (tl == NULL) 132984057Speter return EBADRPC; 133088091Siedowse (a)->va_uid = fxdr_unsigned(uid_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_gid = fxdr_unsigned(gid_t, *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(2 * NFSX_UNSIGNED, md, dpos); 134688091Siedowse if (tl == NULL) 134784057Speter return EBADRPC; 134888091Siedowse (a)->va_size = fxdr_hyper(tl); 134983651Speter } 135088091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 135188091Siedowse if (tl == NULL) 135284057Speter return EBADRPC; 135388091Siedowse switch (fxdr_unsigned(int, *tl)) { 135483651Speter case NFSV3SATTRTIME_TOCLIENT: 135588091Siedowse tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 135688091Siedowse if (tl == NULL) 135784057Speter return EBADRPC; 135888091Siedowse fxdr_nfsv3time(tl, &(a)->va_atime); 135983651Speter break; 136083651Speter case NFSV3SATTRTIME_TOSERVER: 136183651Speter getnanotime(&(a)->va_atime); 136283651Speter break; 136383651Speter } 136488091Siedowse tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 136588091Siedowse if (tl == NULL) 136684057Speter return EBADRPC; 136788091Siedowse switch (fxdr_unsigned(int, *tl)) { 136883651Speter case NFSV3SATTRTIME_TOCLIENT: 136988091Siedowse tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 137088091Siedowse if (tl == NULL) 137184057Speter return EBADRPC; 137288091Siedowse fxdr_nfsv3time(tl, &(a)->va_mtime); 137383651Speter break; 137483651Speter case NFSV3SATTRTIME_TOSERVER: 137583651Speter getnanotime(&(a)->va_mtime); 137683651Speter break; 137783651Speter } 137883651Speter return 0; 137983651Speter} 1380