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