1139823Simp/*- 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 * 4. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes * 3236503Speter * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 331541Srgrimes */ 341541Srgrimes 3583651Speter#include <sys/cdefs.h> 3683651Speter__FBSDID("$FreeBSD$"); 3783651Speter 381541Srgrimes/* 391541Srgrimes * These functions support the macros and help fiddle mbuf chains for 401541Srgrimes * the nfs op functions. They do things like create the rpc header and 411541Srgrimes * copy data between mbuf chains and uio lists. 421541Srgrimes */ 4383651Speter 44100134Salfred#include "opt_inet6.h" 45100134Salfred 461541Srgrimes#include <sys/param.h> 4748274Speter#include <sys/systm.h> 4848274Speter#include <sys/kernel.h> 4960041Sphk#include <sys/bio.h> 5031886Sbde#include <sys/buf.h> 511541Srgrimes#include <sys/proc.h> 521541Srgrimes#include <sys/mount.h> 531541Srgrimes#include <sys/vnode.h> 541541Srgrimes#include <sys/namei.h> 551541Srgrimes#include <sys/mbuf.h> 56150634Sjhb#include <sys/refcount.h> 571541Srgrimes#include <sys/socket.h> 581541Srgrimes#include <sys/stat.h> 599336Sdfr#include <sys/malloc.h> 6083700Speter#include <sys/module.h> 612997Swollman#include <sys/sysent.h> 622997Swollman#include <sys/syscall.h> 6383651Speter#include <sys/sysproto.h> 641541Srgrimes 653305Sphk#include <vm/vm.h> 6612662Sdg#include <vm/vm_object.h> 6712662Sdg#include <vm/vm_extern.h> 6892783Sjeff#include <vm/uma.h> 693305Sphk 70195202Sdfr#include <rpc/rpc.h> 71195202Sdfr 729336Sdfr#include <nfs/nfsproto.h> 7383651Speter#include <nfsserver/nfs.h> 741541Srgrimes#include <nfs/xdr_subs.h> 7583651Speter#include <nfsserver/nfsm_subs.h> 761541Srgrimes 771541Srgrimes#include <netinet/in.h> 781541Srgrimes 791541Srgrimes/* 801541Srgrimes * Data items converted to xdr at startup, since they are constant 811541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 821541Srgrimes */ 8389094Smsmithu_int32_t nfsrv_nfs_xdrneg1; 84195202Sdfru_int32_t nfsrv_nfs_true, nfsrv_nfs_false; 851541Srgrimes 861541Srgrimes/* And other global data */ 87129639Srwatsonstatic const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, 88129639Srwatson NFLNK, NFNON, NFCHR, NFNON }; 8983651Speter#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 9083651Speter#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 9112911Sphk 9289094Smsmithint nfsrv_ticks; 939336Sdfr 94129639Srwatsonstruct mtx nfsd_mtx; 95129639Srwatson 969336Sdfr/* 979336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 989336Sdfr */ 99129639Srwatsonconst int nfsrv_nfsv3_procid[NFS_NPROCS] = { 1009336Sdfr NFSPROC_NULL, 1019336Sdfr NFSPROC_GETATTR, 1029336Sdfr NFSPROC_SETATTR, 1039336Sdfr NFSPROC_NOOP, 1049336Sdfr NFSPROC_LOOKUP, 1059336Sdfr NFSPROC_READLINK, 1069336Sdfr NFSPROC_READ, 1079336Sdfr NFSPROC_NOOP, 1089336Sdfr NFSPROC_WRITE, 1099336Sdfr NFSPROC_CREATE, 1109336Sdfr NFSPROC_REMOVE, 1119336Sdfr NFSPROC_RENAME, 1129336Sdfr NFSPROC_LINK, 1139336Sdfr NFSPROC_SYMLINK, 1149336Sdfr NFSPROC_MKDIR, 1159336Sdfr NFSPROC_RMDIR, 1169336Sdfr NFSPROC_READDIR, 1179336Sdfr NFSPROC_FSSTAT, 1189336Sdfr NFSPROC_NOOP, 1199336Sdfr NFSPROC_NOOP, 1209336Sdfr NFSPROC_NOOP, 1219336Sdfr NFSPROC_NOOP, 1229336Sdfr NFSPROC_NOOP, 1239336Sdfr}; 1249336Sdfr 1259336Sdfr/* 1269336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1279336Sdfr */ 128129639Srwatsonconst int nfsrvv2_procid[NFS_NPROCS] = { 1299336Sdfr NFSV2PROC_NULL, 1309336Sdfr NFSV2PROC_GETATTR, 1319336Sdfr NFSV2PROC_SETATTR, 1329336Sdfr NFSV2PROC_LOOKUP, 1339336Sdfr NFSV2PROC_NOOP, 1349336Sdfr NFSV2PROC_READLINK, 1359336Sdfr NFSV2PROC_READ, 1369336Sdfr NFSV2PROC_WRITE, 1379336Sdfr NFSV2PROC_CREATE, 1389336Sdfr NFSV2PROC_MKDIR, 1399336Sdfr NFSV2PROC_SYMLINK, 1409336Sdfr NFSV2PROC_CREATE, 1419336Sdfr NFSV2PROC_REMOVE, 1429336Sdfr NFSV2PROC_RMDIR, 1439336Sdfr NFSV2PROC_RENAME, 1449336Sdfr NFSV2PROC_LINK, 1459336Sdfr NFSV2PROC_READDIR, 1469336Sdfr NFSV2PROC_NOOP, 1479336Sdfr NFSV2PROC_STATFS, 1489336Sdfr NFSV2PROC_NOOP, 1499336Sdfr NFSV2PROC_NOOP, 1509336Sdfr NFSV2PROC_NOOP, 1519336Sdfr NFSV2PROC_NOOP, 1529336Sdfr}; 1539336Sdfr 1549336Sdfr/* 1559336Sdfr * Maps errno values to nfs error numbers. 156102236Sphk * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not 157102236Sphk * specifically defined in RFC 1094. 1589336Sdfr */ 159129639Srwatsonstatic const u_char nfsrv_v2errmap[ELAST] = { 160102236Sphk NFSERR_PERM, NFSERR_NOENT, 0, 0, 0, 161102236Sphk NFSERR_NXIO, 0, 0, 0, 0, 162102236Sphk 0, 0, NFSERR_ACCES, 0, 0, 163102236Sphk 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR, 164102236Sphk NFSERR_ISDIR, 0, 0, 0, 0, 165102236Sphk 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS, 166102236Sphk 0, 0, 0, 0, 0, 167102236Sphk 0, 0, 0, 0, 0, 168102236Sphk 0, 0, 0, 0, 0, 169102236Sphk 0, 0, 0, 0, 0, 170102236Sphk 0, 0, 0, 0, 0, 171102236Sphk 0, 0, 0, 0, 0, 172102236Sphk 0, 0, NFSERR_NAMETOL, 0, 0, 173102236Sphk NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE, 174102236Sphk 0 1759336Sdfr}; 1769336Sdfr 1779336Sdfr/* 1789336Sdfr * Maps errno values to nfs error numbers. 1799336Sdfr * Although it is not obvious whether or not NFS clients really care if 1809336Sdfr * a returned error value is in the specified list for the procedure, the 1819336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 1829336Sdfr * X/Open XNFS document is the only specification that defines error values 1839336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 1849336Sdfr * so I have decided to not do this for Version 2. 1859336Sdfr * The first entry is the default error return and the rest are the valid 1869336Sdfr * errors for that RPC in increasing numeric order. 1879336Sdfr */ 188129639Srwatsonstatic const short nfsv3err_null[] = { 1899336Sdfr 0, 1909336Sdfr 0, 1919336Sdfr}; 1929336Sdfr 193129639Srwatsonstatic const short nfsv3err_getattr[] = { 1949336Sdfr NFSERR_IO, 1959336Sdfr NFSERR_IO, 1969336Sdfr NFSERR_STALE, 1979336Sdfr NFSERR_BADHANDLE, 1989336Sdfr NFSERR_SERVERFAULT, 1999336Sdfr 0, 2009336Sdfr}; 2019336Sdfr 202129639Srwatsonstatic const short nfsv3err_setattr[] = { 2039336Sdfr NFSERR_IO, 2049336Sdfr NFSERR_PERM, 2059336Sdfr NFSERR_IO, 2069336Sdfr NFSERR_ACCES, 2079336Sdfr NFSERR_INVAL, 2089336Sdfr NFSERR_NOSPC, 2099336Sdfr NFSERR_ROFS, 2109336Sdfr NFSERR_DQUOT, 2119336Sdfr NFSERR_STALE, 2129336Sdfr NFSERR_BADHANDLE, 2139336Sdfr NFSERR_NOT_SYNC, 2149336Sdfr NFSERR_SERVERFAULT, 2159336Sdfr 0, 2169336Sdfr}; 2179336Sdfr 218129639Srwatsonstatic const short nfsv3err_lookup[] = { 2199336Sdfr NFSERR_IO, 2209336Sdfr NFSERR_NOENT, 2219336Sdfr NFSERR_IO, 2229336Sdfr NFSERR_ACCES, 2239336Sdfr NFSERR_NOTDIR, 2249336Sdfr NFSERR_NAMETOL, 2259336Sdfr NFSERR_STALE, 2269336Sdfr NFSERR_BADHANDLE, 2279336Sdfr NFSERR_SERVERFAULT, 2289336Sdfr 0, 2299336Sdfr}; 2309336Sdfr 231129639Srwatsonstatic const short nfsv3err_access[] = { 2329336Sdfr NFSERR_IO, 2339336Sdfr NFSERR_IO, 2349336Sdfr NFSERR_STALE, 2359336Sdfr NFSERR_BADHANDLE, 2369336Sdfr NFSERR_SERVERFAULT, 2379336Sdfr 0, 2389336Sdfr}; 2399336Sdfr 240129639Srwatsonstatic const short nfsv3err_readlink[] = { 2419336Sdfr NFSERR_IO, 2429336Sdfr NFSERR_IO, 2439336Sdfr NFSERR_ACCES, 2449336Sdfr NFSERR_INVAL, 2459336Sdfr NFSERR_STALE, 2469336Sdfr NFSERR_BADHANDLE, 2479336Sdfr NFSERR_NOTSUPP, 2489336Sdfr NFSERR_SERVERFAULT, 2499336Sdfr 0, 2509336Sdfr}; 2519336Sdfr 252129639Srwatsonstatic const short nfsv3err_read[] = { 2539336Sdfr NFSERR_IO, 2549336Sdfr NFSERR_IO, 2559336Sdfr NFSERR_NXIO, 2569336Sdfr NFSERR_ACCES, 2579336Sdfr NFSERR_INVAL, 2589336Sdfr NFSERR_STALE, 2599336Sdfr NFSERR_BADHANDLE, 2609336Sdfr NFSERR_SERVERFAULT, 2619336Sdfr 0, 2629336Sdfr}; 2639336Sdfr 264129639Srwatsonstatic const short nfsv3err_write[] = { 2659336Sdfr NFSERR_IO, 2669336Sdfr NFSERR_IO, 2679336Sdfr NFSERR_ACCES, 2689336Sdfr NFSERR_INVAL, 2699336Sdfr NFSERR_FBIG, 2709336Sdfr NFSERR_NOSPC, 2719336Sdfr NFSERR_ROFS, 2729336Sdfr NFSERR_DQUOT, 2739336Sdfr NFSERR_STALE, 2749336Sdfr NFSERR_BADHANDLE, 2759336Sdfr NFSERR_SERVERFAULT, 2769336Sdfr 0, 2779336Sdfr}; 2789336Sdfr 279129639Srwatsonstatic const short nfsv3err_create[] = { 2809336Sdfr NFSERR_IO, 2819336Sdfr NFSERR_IO, 2829336Sdfr NFSERR_ACCES, 2839336Sdfr NFSERR_EXIST, 2849336Sdfr NFSERR_NOTDIR, 2859336Sdfr NFSERR_NOSPC, 2869336Sdfr NFSERR_ROFS, 2879336Sdfr NFSERR_NAMETOL, 2889336Sdfr NFSERR_DQUOT, 2899336Sdfr NFSERR_STALE, 2909336Sdfr NFSERR_BADHANDLE, 2919336Sdfr NFSERR_NOTSUPP, 2929336Sdfr NFSERR_SERVERFAULT, 2939336Sdfr 0, 2949336Sdfr}; 2959336Sdfr 296129639Srwatsonstatic const short nfsv3err_mkdir[] = { 2979336Sdfr NFSERR_IO, 2989336Sdfr NFSERR_IO, 2999336Sdfr NFSERR_ACCES, 3009336Sdfr NFSERR_EXIST, 3019336Sdfr NFSERR_NOTDIR, 3029336Sdfr NFSERR_NOSPC, 3039336Sdfr NFSERR_ROFS, 3049336Sdfr NFSERR_NAMETOL, 3059336Sdfr NFSERR_DQUOT, 3069336Sdfr NFSERR_STALE, 3079336Sdfr NFSERR_BADHANDLE, 3089336Sdfr NFSERR_NOTSUPP, 3099336Sdfr NFSERR_SERVERFAULT, 3109336Sdfr 0, 3119336Sdfr}; 3129336Sdfr 313129639Srwatsonstatic const short nfsv3err_symlink[] = { 3149336Sdfr NFSERR_IO, 3159336Sdfr NFSERR_IO, 3169336Sdfr NFSERR_ACCES, 3179336Sdfr NFSERR_EXIST, 3189336Sdfr NFSERR_NOTDIR, 3199336Sdfr NFSERR_NOSPC, 3209336Sdfr NFSERR_ROFS, 3219336Sdfr NFSERR_NAMETOL, 3229336Sdfr NFSERR_DQUOT, 3239336Sdfr NFSERR_STALE, 3249336Sdfr NFSERR_BADHANDLE, 3259336Sdfr NFSERR_NOTSUPP, 3269336Sdfr NFSERR_SERVERFAULT, 3279336Sdfr 0, 3289336Sdfr}; 3299336Sdfr 330129639Srwatsonstatic const short nfsv3err_mknod[] = { 3319336Sdfr NFSERR_IO, 3329336Sdfr NFSERR_IO, 3339336Sdfr NFSERR_ACCES, 3349336Sdfr NFSERR_EXIST, 3359336Sdfr NFSERR_NOTDIR, 3369336Sdfr NFSERR_NOSPC, 3379336Sdfr NFSERR_ROFS, 3389336Sdfr NFSERR_NAMETOL, 3399336Sdfr NFSERR_DQUOT, 3409336Sdfr NFSERR_STALE, 3419336Sdfr NFSERR_BADHANDLE, 3429336Sdfr NFSERR_NOTSUPP, 3439336Sdfr NFSERR_SERVERFAULT, 3449336Sdfr NFSERR_BADTYPE, 3459336Sdfr 0, 3469336Sdfr}; 3479336Sdfr 348129639Srwatsonstatic const short nfsv3err_remove[] = { 3499336Sdfr NFSERR_IO, 3509336Sdfr NFSERR_NOENT, 3519336Sdfr NFSERR_IO, 3529336Sdfr NFSERR_ACCES, 3539336Sdfr NFSERR_NOTDIR, 3549336Sdfr NFSERR_ROFS, 3559336Sdfr NFSERR_NAMETOL, 3569336Sdfr NFSERR_STALE, 3579336Sdfr NFSERR_BADHANDLE, 3589336Sdfr NFSERR_SERVERFAULT, 3599336Sdfr 0, 3609336Sdfr}; 3619336Sdfr 362129639Srwatsonstatic const short nfsv3err_rmdir[] = { 3639336Sdfr NFSERR_IO, 3649336Sdfr NFSERR_NOENT, 3659336Sdfr NFSERR_IO, 3669336Sdfr NFSERR_ACCES, 3679336Sdfr NFSERR_EXIST, 3689336Sdfr NFSERR_NOTDIR, 3699336Sdfr NFSERR_INVAL, 3709336Sdfr NFSERR_ROFS, 3719336Sdfr NFSERR_NAMETOL, 3729336Sdfr NFSERR_NOTEMPTY, 3739336Sdfr NFSERR_STALE, 3749336Sdfr NFSERR_BADHANDLE, 3759336Sdfr NFSERR_NOTSUPP, 3769336Sdfr NFSERR_SERVERFAULT, 3779336Sdfr 0, 3789336Sdfr}; 3799336Sdfr 380129639Srwatsonstatic const short nfsv3err_rename[] = { 3819336Sdfr NFSERR_IO, 3829336Sdfr NFSERR_NOENT, 3839336Sdfr NFSERR_IO, 3849336Sdfr NFSERR_ACCES, 3859336Sdfr NFSERR_EXIST, 3869336Sdfr NFSERR_XDEV, 3879336Sdfr NFSERR_NOTDIR, 3889336Sdfr NFSERR_ISDIR, 3899336Sdfr NFSERR_INVAL, 3909336Sdfr NFSERR_NOSPC, 3919336Sdfr NFSERR_ROFS, 3929336Sdfr NFSERR_MLINK, 3939336Sdfr NFSERR_NAMETOL, 3949336Sdfr NFSERR_NOTEMPTY, 3959336Sdfr NFSERR_DQUOT, 3969336Sdfr NFSERR_STALE, 3979336Sdfr NFSERR_BADHANDLE, 3989336Sdfr NFSERR_NOTSUPP, 3999336Sdfr NFSERR_SERVERFAULT, 4009336Sdfr 0, 4019336Sdfr}; 4029336Sdfr 403129639Srwatsonstatic const short nfsv3err_link[] = { 4049336Sdfr NFSERR_IO, 4059336Sdfr NFSERR_IO, 4069336Sdfr NFSERR_ACCES, 4079336Sdfr NFSERR_EXIST, 4089336Sdfr NFSERR_XDEV, 4099336Sdfr NFSERR_NOTDIR, 4109336Sdfr NFSERR_INVAL, 4119336Sdfr NFSERR_NOSPC, 4129336Sdfr NFSERR_ROFS, 4139336Sdfr NFSERR_MLINK, 4149336Sdfr NFSERR_NAMETOL, 4159336Sdfr NFSERR_DQUOT, 4169336Sdfr NFSERR_STALE, 4179336Sdfr NFSERR_BADHANDLE, 4189336Sdfr NFSERR_NOTSUPP, 4199336Sdfr NFSERR_SERVERFAULT, 4209336Sdfr 0, 4219336Sdfr}; 4229336Sdfr 423129639Srwatsonstatic const short nfsv3err_readdir[] = { 4249336Sdfr NFSERR_IO, 4259336Sdfr NFSERR_IO, 4269336Sdfr NFSERR_ACCES, 4279336Sdfr NFSERR_NOTDIR, 4289336Sdfr NFSERR_STALE, 4299336Sdfr NFSERR_BADHANDLE, 4309336Sdfr NFSERR_BAD_COOKIE, 4319336Sdfr NFSERR_TOOSMALL, 4329336Sdfr NFSERR_SERVERFAULT, 4339336Sdfr 0, 4349336Sdfr}; 4359336Sdfr 436129639Srwatsonstatic const short nfsv3err_readdirplus[] = { 4379336Sdfr NFSERR_IO, 4389336Sdfr NFSERR_IO, 4399336Sdfr NFSERR_ACCES, 4409336Sdfr NFSERR_NOTDIR, 4419336Sdfr NFSERR_STALE, 4429336Sdfr NFSERR_BADHANDLE, 4439336Sdfr NFSERR_BAD_COOKIE, 4449336Sdfr NFSERR_NOTSUPP, 4459336Sdfr NFSERR_TOOSMALL, 4469336Sdfr NFSERR_SERVERFAULT, 4479336Sdfr 0, 4489336Sdfr}; 4499336Sdfr 450129639Srwatsonstatic const short nfsv3err_fsstat[] = { 4519336Sdfr NFSERR_IO, 4529336Sdfr NFSERR_IO, 4539336Sdfr NFSERR_STALE, 4549336Sdfr NFSERR_BADHANDLE, 4559336Sdfr NFSERR_SERVERFAULT, 4569336Sdfr 0, 4579336Sdfr}; 4589336Sdfr 459129639Srwatsonstatic const short nfsv3err_fsinfo[] = { 4609336Sdfr NFSERR_STALE, 4619336Sdfr NFSERR_STALE, 4629336Sdfr NFSERR_BADHANDLE, 4639336Sdfr NFSERR_SERVERFAULT, 4649336Sdfr 0, 4659336Sdfr}; 4669336Sdfr 467129639Srwatsonstatic const short nfsv3err_pathconf[] = { 4689336Sdfr NFSERR_STALE, 4699336Sdfr NFSERR_STALE, 4709336Sdfr NFSERR_BADHANDLE, 4719336Sdfr NFSERR_SERVERFAULT, 4729336Sdfr 0, 4739336Sdfr}; 4749336Sdfr 475129639Srwatsonstatic const short nfsv3err_commit[] = { 4769336Sdfr NFSERR_IO, 4779336Sdfr NFSERR_IO, 4789336Sdfr NFSERR_STALE, 4799336Sdfr NFSERR_BADHANDLE, 4809336Sdfr NFSERR_SERVERFAULT, 4819336Sdfr 0, 4829336Sdfr}; 4839336Sdfr 484129639Srwatsonstatic const short *nfsrv_v3errmap[] = { 4859336Sdfr nfsv3err_null, 4869336Sdfr nfsv3err_getattr, 4879336Sdfr nfsv3err_setattr, 4889336Sdfr nfsv3err_lookup, 4899336Sdfr nfsv3err_access, 4909336Sdfr nfsv3err_readlink, 4919336Sdfr nfsv3err_read, 4929336Sdfr nfsv3err_write, 4939336Sdfr nfsv3err_create, 4949336Sdfr nfsv3err_mkdir, 4959336Sdfr nfsv3err_symlink, 4969336Sdfr nfsv3err_mknod, 4979336Sdfr nfsv3err_remove, 4989336Sdfr nfsv3err_rmdir, 4999336Sdfr nfsv3err_rename, 5009336Sdfr nfsv3err_link, 5019336Sdfr nfsv3err_readdir, 5029336Sdfr nfsv3err_readdirplus, 5039336Sdfr nfsv3err_fsstat, 5049336Sdfr nfsv3err_fsinfo, 5059336Sdfr nfsv3err_pathconf, 5069336Sdfr nfsv3err_commit, 5079336Sdfr}; 5089336Sdfr 509190971Srmacklemextern int (*nfsd_call_nfsserver)(struct thread *, struct nfssvc_args *); 510190971Srmacklem 5111541Srgrimes/* 5121541Srgrimes * Called once to initialize data structures... 5131541Srgrimes */ 51483651Speterstatic int 51583700Speternfsrv_modevent(module_t mod, int type, void *data) 5161541Srgrimes{ 517132199Sphk int error = 0; 5181541Srgrimes 51983700Speter switch (type) { 52083700Speter case MOD_LOAD: 521129639Srwatson mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); 52289094Smsmith nfsrv_nfs_true = txdr_unsigned(TRUE); 52389094Smsmith nfsrv_nfs_false = txdr_unsigned(FALSE); 52489094Smsmith nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 52589094Smsmith nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 52689094Smsmith if (nfsrv_ticks < 1) 52789094Smsmith nfsrv_ticks = 1; 52883651Speter 529129639Srwatson NFSD_LOCK(); 53083700Speter nfsrv_init(0); /* Init server data structures */ 531129639Srwatson NFSD_UNLOCK(); 5321541Srgrimes 533190971Srmacklem nfsd_call_nfsserver = nfssvc_nfsserver; 53483700Speter break; 5352997Swollman 536132199Sphk case MOD_UNLOAD: 537129902Sbmilekic if (nfsrv_numnfsd != 0) { 538132199Sphk error = EBUSY; 539132199Sphk break; 540129902Sbmilekic } 54183700Speter 542190971Srmacklem nfsd_call_nfsserver = NULL; 543160881Sjhb callout_drain(&nfsrv_callout); 544129639Srwatson mtx_destroy(&nfsd_mtx); 54583700Speter break; 546132199Sphk default: 547132199Sphk error = EOPNOTSUPP; 548132199Sphk break; 54983700Speter } 550132199Sphk return error; 5511541Srgrimes} 55283700Speterstatic moduledata_t nfsserver_mod = { 55383700Speter "nfsserver", 55483700Speter nfsrv_modevent, 555241394Skevlo NULL, 55683700Speter}; 55783700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 5581541Srgrimes 55983700Speter/* So that loader and kldload(2) can find us, wherever we are.. */ 56083700SpeterMODULE_VERSION(nfsserver, 1); 561190971SrmacklemMODULE_DEPEND(nfsserver, nfssvc, 1, 1, 1); 562184716SdesMODULE_DEPEND(nfsserver, krpc, 1, 1, 1); 563203968SmariusMODULE_DEPEND(nfsserver, nfs_common, 1, 1, 1); 56438894Sbde 5651541Srgrimes/* 56627446Sdfr * Set up nameidata for a lookup() call and do it. 56727446Sdfr * 56827446Sdfr * If pubflag is set, this call is done for a lookup operation on the 56927446Sdfr * public filehandle. In that case we allow crossing mountpoints and 57027446Sdfr * absolute pathnames. However, the caller is expected to check that 57127446Sdfr * the lookup result is within the public fs, and deny access if 57227446Sdfr * it is not. 57348125Sjulian * 57448125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 57548125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 57648125Sjulian * error occurs but the parent was not requested. 57748125Sjulian * 57883651Speter * dirp may be set whether an error is returned or not, and must be 57948125Sjulian * released by the caller. 5801541Srgrimes */ 5811549Srgrimesint 582184588Sdfrnfs_namei(struct nameidata *ndp, struct nfsrv_descript *nfsd, 583184588Sdfr fhandle_t *fhp, int len, struct nfssvc_sock *slp, 584184588Sdfr struct sockaddr *nam, struct mbuf **mdp, 585115301Struckman caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp, 586183103Sattilio int *retdirattr_retp, int pubflag) 5871541Srgrimes{ 58883651Speter int i, rem; 58983651Speter struct mbuf *md; 59083651Speter char *fromcp, *tocp, *cp; 59127446Sdfr struct iovec aiov; 59227446Sdfr struct uio auio; 5931541Srgrimes struct vnode *dp; 59427446Sdfr int error, rdonly, linklen; 5951541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 596115301Struckman int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; 5971541Srgrimes 59899797Sdillon *retdirp = NULL; 599105481Srwatson cnp->cn_flags |= NOMACCHECK; 600111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 60129653Sdyson 6021541Srgrimes /* 6031541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 6041541Srgrimes * and set the various ndp fields appropriately. 6051541Srgrimes */ 6061541Srgrimes fromcp = *dposp; 6071541Srgrimes tocp = cnp->cn_pnbuf; 6081541Srgrimes md = *mdp; 6091541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 6101541Srgrimes for (i = 0; i < len; i++) { 6111541Srgrimes while (rem == 0) { 6121541Srgrimes md = md->m_next; 6131541Srgrimes if (md == NULL) { 6141541Srgrimes error = EBADRPC; 615167665Sjeff goto out; 6161541Srgrimes } 6171541Srgrimes fromcp = mtod(md, caddr_t); 6181541Srgrimes rem = md->m_len; 6191541Srgrimes } 62027446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 6219336Sdfr error = EACCES; 622167665Sjeff goto out; 6231541Srgrimes } 6241541Srgrimes *tocp++ = *fromcp++; 6251541Srgrimes rem--; 6261541Srgrimes } 6271541Srgrimes *tocp = '\0'; 6281541Srgrimes *mdp = md; 6291541Srgrimes *dposp = fromcp; 6301541Srgrimes len = nfsm_rndup(len)-len; 6311541Srgrimes if (len > 0) { 6321541Srgrimes if (rem >= len) 6331541Srgrimes *dposp += len; 63427609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 635167665Sjeff goto out; 6361541Srgrimes } 63727446Sdfr 638216632Spjd if (!pubflag && nfs_ispublicfh(fhp)) 639216632Spjd return (ESTALE); 640216632Spjd 6411541Srgrimes /* 6421541Srgrimes * Extract and set starting directory. 6431541Srgrimes */ 644241896Skib error = nfsrv_fhtovp(fhp, 0, &dp, nfsd, slp, nam, &rdonly); 64527446Sdfr if (error) 6461541Srgrimes goto out; 6471541Srgrimes if (dp->v_type != VDIR) { 648216632Spjd vput(dp); 6491541Srgrimes error = ENOTDIR; 6501541Srgrimes goto out; 6511541Srgrimes } 65227446Sdfr 65327446Sdfr if (rdonly) 65427446Sdfr cnp->cn_flags |= RDONLY; 65527446Sdfr 65648125Sjulian /* 65783651Speter * Set return directory. Reference to dp is implicitly transfered 65848125Sjulian * to the returned pointer 65948125Sjulian */ 66027609Sdfr *retdirp = dp; 661115301Struckman if (v3) { 662115301Struckman *retdirattr_retp = VOP_GETATTR(dp, retdirattrp, 663182371Sattilio ndp->ni_cnd.cn_cred); 664115301Struckman } 66527609Sdfr 666216632Spjd VOP_UNLOCK(dp, 0); 667216632Spjd 66827446Sdfr if (pubflag) { 66927446Sdfr /* 67027446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 67127446Sdfr * and the 'native path' indicator. 67227446Sdfr */ 673111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 67427446Sdfr fromcp = cnp->cn_pnbuf; 67527446Sdfr tocp = cp; 67627446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 67727446Sdfr switch ((unsigned char)*fromcp) { 67827446Sdfr case WEBNFS_NATIVE_CHAR: 67927446Sdfr /* 68027446Sdfr * 'Native' path for us is the same 68127446Sdfr * as a path according to the NFS spec, 68227446Sdfr * just skip the escape char. 68327446Sdfr */ 68427446Sdfr fromcp++; 68527446Sdfr break; 68627446Sdfr /* 68727446Sdfr * More may be added in the future, range 0x80-0xff 68827446Sdfr */ 68927446Sdfr default: 69027446Sdfr error = EIO; 69192783Sjeff uma_zfree(namei_zone, cp); 69227446Sdfr goto out; 69327446Sdfr } 69427446Sdfr } 69527446Sdfr /* 69627446Sdfr * Translate the '%' escapes, URL-style. 69727446Sdfr */ 69827446Sdfr while (*fromcp != '\0') { 69927446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 70027446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 70127446Sdfr fromcp++; 70227446Sdfr *tocp++ = HEXSTRTOI(fromcp); 70327446Sdfr fromcp += 2; 70427446Sdfr continue; 70527446Sdfr } else { 70627446Sdfr error = ENOENT; 70792783Sjeff uma_zfree(namei_zone, cp); 70827446Sdfr goto out; 70927446Sdfr } 71027446Sdfr } else 71127446Sdfr *tocp++ = *fromcp++; 71227446Sdfr } 71327446Sdfr *tocp = '\0'; 71492783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 71527446Sdfr cnp->cn_pnbuf = cp; 71627446Sdfr } 71727446Sdfr 71827446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 71927446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 72027446Sdfr 72127446Sdfr if (pubflag) { 72227446Sdfr ndp->ni_rootdir = rootvnode; 72327446Sdfr ndp->ni_loopcnt = 0; 724167665Sjeff 725241896Skib if (cnp->cn_pnbuf[0] == '/') 72627446Sdfr dp = rootvnode; 72727446Sdfr } else { 72827609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 72927446Sdfr } 73027446Sdfr 73148125Sjulian /* 73248125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 733123608Sjhb * because lookup() will dereference ni_startdir. 73448125Sjulian */ 73548125Sjulian 736183103Sattilio cnp->cn_thread = curthread; 7379336Sdfr VREF(dp); 73848125Sjulian ndp->ni_startdir = dp; 73927446Sdfr 740115301Struckman if (!lockleaf) 741115301Struckman cnp->cn_flags |= LOCKLEAF; 74248125Sjulian for (;;) { 74348125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 74448125Sjulian /* 74548125Sjulian * Call lookup() to do the real work. If an error occurs, 74648125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 74748125Sjulian * we do not have to dereference anything before returning. 74848125Sjulian * In either case ni_startdir will be dereferenced and NULLed 74948125Sjulian * out. 75048125Sjulian */ 75148125Sjulian error = lookup(ndp); 75248125Sjulian if (error) 75348125Sjulian break; 75448125Sjulian 75548125Sjulian /* 75683651Speter * Check for encountering a symbolic link. Trivial 75748125Sjulian * termination occurs if no symlink encountered. 75848125Sjulian * Note: zfree is safe because error is 0, so we will 75948125Sjulian * not zfree it again when we break. 76048125Sjulian */ 76148125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 76248125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 76348125Sjulian cnp->cn_flags |= HASBUF; 76448125Sjulian else 76592783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 766115301Struckman if (ndp->ni_vp && !lockleaf) 767175294Sattilio VOP_UNLOCK(ndp->ni_vp, 0); 76848125Sjulian break; 76927446Sdfr } 77048125Sjulian 77148125Sjulian /* 77248125Sjulian * Validate symlink 77348125Sjulian */ 7741541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 775175294Sattilio VOP_UNLOCK(ndp->ni_dvp, 0); 77627446Sdfr if (!pubflag) { 77727446Sdfr error = EINVAL; 77848125Sjulian goto badlink2; 77927446Sdfr } 78027446Sdfr 78127446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 78227446Sdfr error = ELOOP; 78348125Sjulian goto badlink2; 78427446Sdfr } 78527609Sdfr if (ndp->ni_pathlen > 1) 786111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 7871541Srgrimes else 78827446Sdfr cp = cnp->cn_pnbuf; 78927446Sdfr aiov.iov_base = cp; 79027446Sdfr aiov.iov_len = MAXPATHLEN; 79127446Sdfr auio.uio_iov = &aiov; 79227446Sdfr auio.uio_iovcnt = 1; 79327446Sdfr auio.uio_offset = 0; 79427446Sdfr auio.uio_rw = UIO_READ; 79527446Sdfr auio.uio_segflg = UIO_SYSSPACE; 79699797Sdillon auio.uio_td = NULL; 79727446Sdfr auio.uio_resid = MAXPATHLEN; 79827446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 79927446Sdfr if (error) { 80048125Sjulian badlink1: 80127446Sdfr if (ndp->ni_pathlen > 1) 80292783Sjeff uma_zfree(namei_zone, cp); 80348125Sjulian badlink2: 804155160Sjeff vput(ndp->ni_vp); 80548125Sjulian vrele(ndp->ni_dvp); 80627446Sdfr break; 80727446Sdfr } 80827446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 80927446Sdfr if (linklen == 0) { 81027446Sdfr error = ENOENT; 81148125Sjulian goto badlink1; 81227446Sdfr } 81327446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 81427446Sdfr error = ENAMETOOLONG; 81548125Sjulian goto badlink1; 81627446Sdfr } 81748125Sjulian 81848125Sjulian /* 81948125Sjulian * Adjust or replace path 82048125Sjulian */ 82127446Sdfr if (ndp->ni_pathlen > 1) { 82227446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 82392783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 82427446Sdfr cnp->cn_pnbuf = cp; 82527446Sdfr } else 82627446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 82727446Sdfr ndp->ni_pathlen += linklen; 82848125Sjulian 82927446Sdfr /* 83083651Speter * Cleanup refs for next loop and check if root directory 83183651Speter * should replace current directory. Normally ni_dvp 83248125Sjulian * becomes the new base directory and is cleaned up when 83348125Sjulian * we loop. Explicitly null pointers after invalidation 83448125Sjulian * to clarify operation. 83527446Sdfr */ 83648125Sjulian vput(ndp->ni_vp); 83748125Sjulian ndp->ni_vp = NULL; 83848125Sjulian 83927446Sdfr if (cnp->cn_pnbuf[0] == '/') { 84048125Sjulian vrele(ndp->ni_dvp); 84148125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 84248125Sjulian VREF(ndp->ni_dvp); 84327446Sdfr } 84448125Sjulian ndp->ni_startdir = ndp->ni_dvp; 84548125Sjulian ndp->ni_dvp = NULL; 8461541Srgrimes } 847115301Struckman if (!lockleaf) 848115301Struckman cnp->cn_flags &= ~LOCKLEAF; 84948125Sjulian 85048125Sjulian /* 85148125Sjulian * nfs_namei() guarentees that fields will not contain garbage 85248125Sjulian * whether an error occurs or not. This allows the caller to track 85348125Sjulian * cleanup state trivially. 85448125Sjulian */ 8551541Srgrimesout: 85648125Sjulian if (error) { 85792783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 85848125Sjulian ndp->ni_vp = NULL; 85948125Sjulian ndp->ni_dvp = NULL; 86048125Sjulian ndp->ni_startdir = NULL; 86148125Sjulian cnp->cn_flags &= ~HASBUF; 86248125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 86348125Sjulian ndp->ni_dvp = NULL; 86448125Sjulian } 8651541Srgrimes return (error); 8661541Srgrimes} 8671541Srgrimes 8681541Srgrimes/* 8691541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 8701541Srgrimes * boundary and only trims off the back end 8711541Srgrimes */ 8721541Srgrimesvoid 87383651Speternfsm_adj(struct mbuf *mp, int len, int nul) 8741541Srgrimes{ 87583651Speter struct mbuf *m; 87683651Speter int count, i; 87783651Speter char *cp; 8781541Srgrimes 8791541Srgrimes /* 8801541Srgrimes * Trim from tail. Scan the mbuf chain, 8811541Srgrimes * calculating its length and finding the last mbuf. 8821541Srgrimes * If the adjustment only affects this mbuf, then just 8831541Srgrimes * adjust and return. Otherwise, rescan and truncate 8841541Srgrimes * after the remaining size. 8851541Srgrimes */ 8861541Srgrimes count = 0; 8871541Srgrimes m = mp; 8881541Srgrimes for (;;) { 8891541Srgrimes count += m->m_len; 89099797Sdillon if (m->m_next == NULL) 8911541Srgrimes break; 8921541Srgrimes m = m->m_next; 8931541Srgrimes } 8941541Srgrimes if (m->m_len > len) { 8951541Srgrimes m->m_len -= len; 8961541Srgrimes if (nul > 0) { 8971541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 8981541Srgrimes for (i = 0; i < nul; i++) 8991541Srgrimes *cp++ = '\0'; 9001541Srgrimes } 9011541Srgrimes return; 9021541Srgrimes } 9031541Srgrimes count -= len; 9041541Srgrimes if (count < 0) 9051541Srgrimes count = 0; 9061541Srgrimes /* 9071541Srgrimes * Correct length for chain is "count". 9081541Srgrimes * Find the mbuf with last data, adjust its length, 9091541Srgrimes * and toss data from remaining mbufs on chain. 9101541Srgrimes */ 9111541Srgrimes for (m = mp; m; m = m->m_next) { 9121541Srgrimes if (m->m_len >= count) { 9131541Srgrimes m->m_len = count; 9141541Srgrimes if (nul > 0) { 9151541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9161541Srgrimes for (i = 0; i < nul; i++) 9171541Srgrimes *cp++ = '\0'; 9181541Srgrimes } 919144246Ssam if (m->m_next != NULL) { 920144246Ssam m_freem(m->m_next); 921144246Ssam m->m_next = NULL; 922144246Ssam } 9231541Srgrimes break; 9241541Srgrimes } 9251541Srgrimes count -= m->m_len; 9261541Srgrimes } 9271541Srgrimes} 9281541Srgrimes 9291541Srgrimes/* 9309336Sdfr * Make these functions instead of macros, so that the kernel text size 9319336Sdfr * doesn't get too big... 9329336Sdfr */ 9339336Sdfrvoid 93483651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 93583651Speter struct vattr *before_vap, int after_ret, struct vattr *after_vap, 93683651Speter struct mbuf **mbp, char **bposp) 9379336Sdfr{ 93883651Speter struct mbuf *mb = *mbp; 93983651Speter char *bpos = *bposp; 94083651Speter u_int32_t *tl; 9419336Sdfr 9429336Sdfr if (before_ret) { 94384002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 94489094Smsmith *tl = nfsrv_nfs_false; 9459336Sdfr } else { 94684002Speter tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 94789094Smsmith *tl++ = nfsrv_nfs_true; 94847751Speter txdr_hyper(before_vap->va_size, tl); 9499336Sdfr tl += 2; 9509336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 9519336Sdfr tl += 2; 9529336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 9539336Sdfr } 9549336Sdfr *bposp = bpos; 9559336Sdfr *mbp = mb; 9569336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 9579336Sdfr} 9589336Sdfr 9599336Sdfrvoid 96083651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 96183651Speter struct vattr *after_vap, struct mbuf **mbp, char **bposp) 9629336Sdfr{ 96383651Speter struct mbuf *mb = *mbp; 96483651Speter char *bpos = *bposp; 96583651Speter u_int32_t *tl; 96683651Speter struct nfs_fattr *fp; 9679336Sdfr 9689336Sdfr if (after_ret) { 96984002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 97089094Smsmith *tl = nfsrv_nfs_false; 9719336Sdfr } else { 97284002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 97389094Smsmith *tl++ = nfsrv_nfs_true; 9749336Sdfr fp = (struct nfs_fattr *)tl; 9759336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 9769336Sdfr } 9779336Sdfr *mbp = mb; 9789336Sdfr *bposp = bpos; 9799336Sdfr} 9809336Sdfr 9819336Sdfrvoid 98283651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 98383651Speter struct nfs_fattr *fp) 9849336Sdfr{ 9859336Sdfr 9869336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 9879336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 9889336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 9899336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 9909336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 9919336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 99247751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 99347751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 994187830Sed fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 995187830Sed fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 9969336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 9979336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 9989336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 9999336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 10009336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 10019336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 10029336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 10039336Sdfr } else { 10049336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 10059336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 10069336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 10079336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 10089336Sdfr if (vap->va_type == VFIFO) 10099336Sdfr fp->fa2_rdev = 0xffffffff; 10109336Sdfr else 10119336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 10129336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 10139336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 10149336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 10159336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 10169336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 10179336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 10189336Sdfr } 10199336Sdfr} 10209336Sdfr 10219336Sdfr/* 10221541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10231541Srgrimes * - look up fsid in mount list (if not found ret error) 10241541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10251541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10261541Srgrimes */ 10271549Srgrimesint 1028241896Skibnfsrv_fhtovp(fhandle_t *fhp, int flags, struct vnode **vpp, 1029184588Sdfr struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1030216632Spjd struct sockaddr *nam, int *rdonlyp) 10311541Srgrimes{ 103283651Speter struct mount *mp; 103383651Speter int i; 1034184588Sdfr struct ucred *cred, *credanon; 10351541Srgrimes int error, exflags; 103636534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 103736534Speter struct sockaddr_int *saddr; 103836534Speter#endif 1039184588Sdfr int credflavor; 1040184588Sdfr int numsecflavors, *secflavors; 1041184693Sdfr int authsys; 1042184588Sdfr int v3 = nfsd->nd_flag & ND_NFSV3; 1043184588Sdfr int mountreq; 10441541Srgrimes 104599797Sdillon *vpp = NULL; 104627446Sdfr 104727446Sdfr if (nfs_ispublicfh(fhp)) { 1048216632Spjd if (!nfs_pub.np_valid) 104927446Sdfr return (ESTALE); 105027446Sdfr fhp = &nfs_pub.np_handle; 105127446Sdfr } 105227446Sdfr 1053185432Skib mp = vfs_busyfs(&fhp->fh_fsid); 10543305Sphk if (!mp) 10551541Srgrimes return (ESTALE); 1056184588Sdfr error = VFS_CHECKEXP(mp, nam, &exflags, &credanon, 1057184588Sdfr &numsecflavors, &secflavors); 1058185432Skib if (error) { 1059185432Skib vfs_unbusy(mp); 1060129639Srwatson goto out; 1061185432Skib } 1062184693Sdfr if (numsecflavors == 0) { 1063184693Sdfr /* 1064184693Sdfr * This can happen if the system is running with an 1065184693Sdfr * old mountd that doesn't pass in a secflavor list. 1066184693Sdfr */ 1067184693Sdfr numsecflavors = 1; 1068195202Sdfr authsys = AUTH_SYS; 1069184693Sdfr secflavors = &authsys; 1070184693Sdfr } 1071184588Sdfr credflavor = nfsd->nd_credflavor; 1072184588Sdfr for (i = 0; i < numsecflavors; i++) { 1073184588Sdfr if (secflavors[i] == credflavor) 1074184588Sdfr break; 1075184588Sdfr } 1076184588Sdfr if (i == numsecflavors) { 1077184588Sdfr /* 1078184588Sdfr * RFC 2623 section 2.3.2 - allow certain procedures 1079184588Sdfr * used at NFS client mount time even if they have 1080184588Sdfr * weak authentication. 1081184588Sdfr */ 1082184588Sdfr mountreq = FALSE; 1083184588Sdfr if (v3) { 1084184868Sdfr if (nfsd->nd_procnum == NFSPROC_FSINFO 1085184868Sdfr || nfsd->nd_procnum == NFSPROC_GETATTR) 1086184588Sdfr mountreq = TRUE; 1087184588Sdfr } else { 1088184588Sdfr if (nfsd->nd_procnum == NFSPROC_FSSTAT 1089184588Sdfr || nfsd->nd_procnum == NFSPROC_GETATTR) 1090184588Sdfr mountreq = TRUE; 1091184588Sdfr } 1092184588Sdfr if (!mountreq) { 1093184868Sdfr error = NFSERR_AUTHERR | AUTH_TOOWEAK; 1094185432Skib vfs_unbusy(mp); 1095184588Sdfr goto out; 1096184588Sdfr } 1097184588Sdfr } 1098222167Srmacklem error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, vpp); 1099216632Spjd if (error) { 1100205661Srmacklem /* Make sure the server replies ESTALE to the client. */ 1101205661Srmacklem error = ESTALE; 1102216632Spjd vfs_unbusy(mp); 1103129639Srwatson goto out; 1104216632Spjd } 110536534Speter#ifdef MNT_EXNORESPORT 110636534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 110736534Speter saddr = (struct sockaddr_in *)nam; 1108100134Salfred if ((saddr->sin_family == AF_INET || 1109100134Salfred saddr->sin_family == AF_INET6) && 1110100134Salfred /* same code for INET and INET6: sin*_port at same offet */ 111136534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 111236534Speter vput(*vpp); 111354485Sdillon *vpp = NULL; 1114129639Srwatson error = NFSERR_AUTHERR | AUTH_TOOWEAK; 1115216631Spjd vfs_unbusy(mp); 1116216631Spjd goto out; 111736534Speter } 111836534Speter } 111936534Speter#endif 11201541Srgrimes /* 11211541Srgrimes * Check/setup credentials. 11221541Srgrimes */ 1123184588Sdfr cred = nfsd->nd_cr; 112483651Speter if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 11251541Srgrimes cred->cr_uid = credanon->cr_uid; 1126194498Sbrooks crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups); 11271541Srgrimes } 11281541Srgrimes if (exflags & MNT_EXRDONLY) 11291541Srgrimes *rdonlyp = 1; 11301541Srgrimes else 11311541Srgrimes *rdonlyp = 0; 11327969Sdyson 1133216632Spjd if (!(flags & NFSRV_FLAG_BUSY)) 1134216632Spjd vfs_unbusy(mp); 1135129639Srwatsonout: 1136191940Skan if (credanon != NULL) 1137191940Skan crfree(credanon); 1138191940Skan 1139164585Srwatson return (error); 1140164585Srwatson} 1141164585Srwatson 1142164585Srwatson 114327446Sdfr/* 114427446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 114527446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 114627446Sdfr * transformed this to all zeroes in both cases, so check for it. 114727446Sdfr */ 114827446Sdfrint 114983651Speternfs_ispublicfh(fhandle_t *fhp) 115027446Sdfr{ 115127446Sdfr char *cp = (char *)fhp; 115227446Sdfr int i; 115327446Sdfr 1154129639Srwatson NFSD_LOCK_DONTCARE(); 1155129639Srwatson 115627446Sdfr for (i = 0; i < NFSX_V3FH; i++) 115727446Sdfr if (*cp++ != 0) 115827446Sdfr return (FALSE); 115927446Sdfr return (TRUE); 116027446Sdfr} 116183651Speter 11621541Srgrimes/* 11639336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 11649336Sdfr * numbers not specified for the associated procedure. 11659336Sdfr */ 11665455Sdgint 116783651Speternfsrv_errmap(struct nfsrv_descript *nd, int err) 11689336Sdfr{ 1169129639Srwatson const short *defaulterrp, *errp; 1170102236Sphk int e; 11719336Sdfr 1172129639Srwatson 11739336Sdfr if (nd->nd_flag & ND_NFSV3) { 11749336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 11759336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 11769336Sdfr while (*++errp) { 11779336Sdfr if (*errp == err) 11789336Sdfr return (err); 11799336Sdfr else if (*errp > err) 11809336Sdfr break; 11819336Sdfr } 11829336Sdfr return ((int)*defaulterrp); 11839336Sdfr } else 11849336Sdfr return (err & 0xffff); 11859336Sdfr } 1186102236Sphk e = 0; 11879336Sdfr if (err <= ELAST) 1188102236Sphk e = nfsrv_v2errmap[err - 1]; 1189102236Sphk if (e != 0) 1190102236Sphk return (e); 11919336Sdfr return (NFSERR_IO); 11929336Sdfr} 11939336Sdfr 119436503Speter/* 119536503Speter * Sort the group list in increasing numerical order. 119636503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 119736503Speter * that used to be here.) 119836503Speter */ 119936503Spetervoid 120083651Speternfsrvw_sort(gid_t *list, int num) 120136503Speter{ 120283651Speter int i, j; 120336503Speter gid_t v; 120436503Speter 120536503Speter /* Insertion sort. */ 120636503Speter for (i = 1; i < num; i++) { 120736503Speter v = list[i]; 120836503Speter /* find correct slot for value v, moving others up */ 120936503Speter for (j = i; --j >= 0 && v < list[j];) 121036503Speter list[j + 1] = list[j]; 121136503Speter list[j + 1] = v; 121236503Speter } 121336503Speter} 121436503Speter 121536503Speter/* 121683651Speter * Helper functions for macros. 121783651Speter */ 121883651Speter 121983651Spetervoid 122088091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 122183651Speter{ 122288091Siedowse u_int32_t *tl; 122383651Speter 122483651Speter if (v3) { 122588091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 122688091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 122788091Siedowse bcopy(f, tl, NFSX_V3FH); 122883651Speter } else { 122988091Siedowse tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 123088091Siedowse bcopy(f, tl, NFSX_V2FH); 123183651Speter } 123283651Speter} 123383651Speter 123483651Spetervoid 123588091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 123683651Speter{ 123788091Siedowse u_int32_t *tl; 123884002Speter 123988091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 124089094Smsmith *tl++ = nfsrv_nfs_true; 124188091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 124288091Siedowse bcopy(f, tl, NFSX_V3FH); 124383651Speter} 124483651Speter 124583651Speterint 124688091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 124783651Speter{ 124888091Siedowse u_int32_t *tl; 124983651Speter 1250140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 125188091Siedowse if (tl == NULL) 125284057Speter return EBADRPC; 125388091Siedowse *s = fxdr_unsigned(int32_t, *tl); 125483651Speter if (*s > m || *s <= 0) 125583651Speter return EBADRPC; 125683651Speter return 0; 125783651Speter} 125883651Speter 125983651Speterint 1260106264Sjeffnfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 126183651Speter{ 126288091Siedowse u_int32_t *tl; 126383651Speter 1264129639Srwatson NFSD_LOCK_DONTCARE(); 1265129639Srwatson 1266140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 126788091Siedowse if (tl == NULL) 126884057Speter return EBADRPC; 126988091Siedowse *s = fxdr_unsigned(int32_t, *tl); 1270106264Sjeff if (*s > m) 127183651Speter return NFSERR_NAMETOL; 127283651Speter if (*s <= 0) 127383651Speter return EBADRPC; 127483651Speter return 0; 127583651Speter} 127683651Speter 1277165739Shrsint 1278165739Shrsnfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1279165739Shrs{ 1280165739Shrs u_int32_t *tl; 1281165739Shrs 1282165739Shrs tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1283165739Shrs if (tl == NULL) 1284165739Shrs return EBADRPC; 1285165739Shrs *s = fxdr_unsigned(int32_t, *tl); 1286165739Shrs if (*s > m) 1287165739Shrs return NFSERR_NAMETOL; 1288165739Shrs if (*s < 0) 1289165739Shrs return EBADRPC; 1290165739Shrs return 0; 1291165739Shrs} 1292165739Shrs 129383651Spetervoid 129483651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 1295167665Sjeff char **bp, char **be, caddr_t bpos) 129683651Speter{ 129783651Speter struct mbuf *nmp; 129883651Speter 1299167665Sjeff NFSD_UNLOCK_ASSERT(); 1300129639Srwatson 130183651Speter if (*bp >= *be) { 130283651Speter if (*mp == mb) 130383651Speter (*mp)->m_len += *bp - bpos; 1304243882Sglebius MGET(nmp, M_WAITOK, MT_DATA); 1305243882Sglebius MCLGET(nmp, M_WAITOK); 130683651Speter nmp->m_len = NFSMSIZ(nmp); 130783651Speter (*mp)->m_next = nmp; 130883651Speter *mp = nmp; 130983651Speter *bp = mtod(*mp, caddr_t); 131083651Speter *be = *bp + (*mp)->m_len; 131183651Speter } 131283651Speter *tl = (u_int32_t *)*bp; 131383651Speter} 131483651Speter 131583651Speterint 1316184588Sdfrnfsm_srvmtofh_xx(fhandle_t *f, int v3, struct mbuf **md, caddr_t *dpos) 131783651Speter{ 131888091Siedowse u_int32_t *tl; 131983651Speter int fhlen; 132083651Speter 1321184588Sdfr if (v3) { 1322140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 132388091Siedowse if (tl == NULL) 132484057Speter return EBADRPC; 132588091Siedowse fhlen = fxdr_unsigned(int, *tl); 132683651Speter if (fhlen != 0 && fhlen != NFSX_V3FH) 132783651Speter return EBADRPC; 132883651Speter } else { 132983651Speter fhlen = NFSX_V2FH; 133083651Speter } 133183651Speter if (fhlen != 0) { 1332140495Sps tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos); 133388091Siedowse if (tl == NULL) 133484057Speter return EBADRPC; 133588091Siedowse bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 133683651Speter } else { 133783651Speter bzero((caddr_t)(f), NFSX_V3FH); 133883651Speter } 133983651Speter return 0; 134083651Speter} 134183651Speter 134283651Speterint 134388091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 134483651Speter{ 134588091Siedowse u_int32_t *tl; 1346157391Scel int toclient = 0; 134783651Speter 1348140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 134988091Siedowse if (tl == NULL) 135084057Speter return EBADRPC; 135189094Smsmith if (*tl == nfsrv_nfs_true) { 1352140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 135388091Siedowse if (tl == NULL) 135484057Speter return EBADRPC; 135588091Siedowse (a)->va_mode = nfstov_mode(*tl); 135683651Speter } 1357140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 135888091Siedowse if (tl == NULL) 135984057Speter return EBADRPC; 136089094Smsmith if (*tl == nfsrv_nfs_true) { 1361140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 136288091Siedowse if (tl == NULL) 136384057Speter return EBADRPC; 136488091Siedowse (a)->va_uid = fxdr_unsigned(uid_t, *tl); 136583651Speter } 1366140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 136788091Siedowse if (tl == NULL) 136884057Speter return EBADRPC; 136989094Smsmith if (*tl == nfsrv_nfs_true) { 1370140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 137188091Siedowse if (tl == NULL) 137284057Speter return EBADRPC; 137388091Siedowse (a)->va_gid = fxdr_unsigned(gid_t, *tl); 137483651Speter } 1375140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 137688091Siedowse if (tl == NULL) 137784057Speter return EBADRPC; 137889094Smsmith if (*tl == nfsrv_nfs_true) { 1379140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 138088091Siedowse if (tl == NULL) 138184057Speter return EBADRPC; 138288091Siedowse (a)->va_size = fxdr_hyper(tl); 138383651Speter } 1384140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 138588091Siedowse if (tl == NULL) 138684057Speter return EBADRPC; 138788091Siedowse switch (fxdr_unsigned(int, *tl)) { 138883651Speter case NFSV3SATTRTIME_TOCLIENT: 1389140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 139088091Siedowse if (tl == NULL) 139184057Speter return EBADRPC; 139288091Siedowse fxdr_nfsv3time(tl, &(a)->va_atime); 1393157391Scel toclient = 1; 139483651Speter break; 139583651Speter case NFSV3SATTRTIME_TOSERVER: 1396245611Sjhb vfs_timestamp(&a->va_atime); 1397157391Scel a->va_vaflags |= VA_UTIMES_NULL; 139883651Speter break; 139983651Speter } 1400140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 140188091Siedowse if (tl == NULL) 140284057Speter return EBADRPC; 140388091Siedowse switch (fxdr_unsigned(int, *tl)) { 140483651Speter case NFSV3SATTRTIME_TOCLIENT: 1405140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 140688091Siedowse if (tl == NULL) 140784057Speter return EBADRPC; 140888091Siedowse fxdr_nfsv3time(tl, &(a)->va_mtime); 1409157391Scel a->va_vaflags &= ~VA_UTIMES_NULL; 141083651Speter break; 141183651Speter case NFSV3SATTRTIME_TOSERVER: 1412245611Sjhb vfs_timestamp(&a->va_mtime); 1413157391Scel if (toclient == 0) 1414157391Scel a->va_vaflags |= VA_UTIMES_NULL; 141583651Speter break; 141683651Speter } 141783651Speter return 0; 141883651Speter} 1419