nfs_srvsubs.c revision 102236
162587Sitojun/* 295023Ssuz * Copyright (c) 1989, 1993 362587Sitojun * The Regents of the University of California. All rights reserved. 4139826Simp * 553541Sshin * This code is derived from software contributed to Berkeley by 653541Sshin * Rick Macklem at The University of Guelph. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. All advertising materials mentioning features or use of this software 1753541Sshin * must display the following acknowledgement: 1853541Sshin * This product includes software developed by the University of 1953541Sshin * California, Berkeley and its contributors. 2053541Sshin * 4. Neither the name of the University nor the names of its contributors 2153541Sshin * may be used to endorse or promote products derived from this software 2253541Sshin * without specific prior written permission. 2353541Sshin * 2453541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2553541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2653541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2753541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2853541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2953541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3053541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3153541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3253541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3362587Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3462587Sitojun * SUCH DAMAGE. 35142215Sglebius * 36142215Sglebius * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 3755009Sshin * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 102236 2002-08-21 19:28:44Z phk $ 3853541Sshin */ 3953541Sshin 4053541Sshin#include <sys/cdefs.h> 4153541Sshin__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 102236 2002-08-21 19:28:44Z phk $"); 4253541Sshin 4353541Sshin/* 4453541Sshin * These functions support the macros and help fiddle mbuf chains for 4553541Sshin * the nfs op functions. They do things like create the rpc header and 4653541Sshin * copy data between mbuf chains and uio lists. 4753541Sshin */ 4853541Sshin 4978064Sume#include "opt_inet6.h" 5053541Sshin 5153541Sshin#include <sys/param.h> 5253541Sshin#include <sys/systm.h> 5353541Sshin#include <sys/kernel.h> 54147306Sbrooks#include <sys/bio.h> 5553541Sshin#include <sys/buf.h> 5653541Sshin#include <sys/proc.h> 5753541Sshin#include <sys/mount.h> 5853541Sshin#include <sys/vnode.h> 5953541Sshin#include <sys/namei.h> 60151477Ssuz#include <sys/mbuf.h> 6162587Sitojun#include <sys/socket.h> 6253541Sshin#include <sys/stat.h> 63148385Sume#include <sys/malloc.h> 6453541Sshin#include <sys/module.h> 6562587Sitojun#include <sys/sysent.h> 6653541Sshin#include <sys/syscall.h> 67142215Sglebius#include <sys/sysproto.h> 68142215Sglebius 69142215Sglebius#include <vm/vm.h> 70142215Sglebius#include <vm/vm_object.h> 7162587Sitojun#include <vm/vm_extern.h> 7253541Sshin#include <vm/uma.h> 7362587Sitojun 7462587Sitojun#include <nfs/rpcv2.h> 7578064Sume#include <nfs/nfsproto.h> 7678064Sume#include <nfsserver/nfs.h> 7762587Sitojun#include <nfs/xdr_subs.h> 7862587Sitojun#include <nfsserver/nfsm_subs.h> 7962587Sitojun 8062587Sitojun#include <netinet/in.h> 8153541Sshin 8262587Sitojun/* 8362587Sitojun * Data items converted to xdr at startup, since they are constant 8453541Sshin * This is kinda hokey, but may save a little time doing byte swaps 8553541Sshin */ 86108470Sschweikhu_int32_t nfsrv_nfs_xdrneg1; 8753541Sshinu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply, 8853541Sshin nfsrv_rpc_msgdenied, nfsrv_rpc_autherr, 89148987Sume nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted; 9053541Sshinu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false; 9153541Sshin 9253541Sshin/* And other global data */ 9353541Sshinstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 9453541Sshin NFNON, NFCHR, NFNON }; 9553541Sshin#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 9653541Sshin#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 9753541Sshin 9862587Sitojunint nfsrv_ticks; 9953541Sshin 10053541Sshinstruct nfssvc_sockhead nfssvc_sockhead; 10162587Sitojunint nfssvc_sockhead_flag; 10253541Sshinstruct nfsd_head nfsd_head; 10353541Sshinint nfsd_head_flag; 104142215Sglebius 10553541Sshinstatic int nfs_prev_nfssvc_sy_narg; 10653541Sshinstatic sy_call_t *nfs_prev_nfssvc_sy_call; 10753541Sshin 10853541Sshin/* 10962587Sitojun * Mapping of old NFS Version 2 RPC numbers to generic numbers. 110165118Sbz */ 11153541Sshinint nfsrv_nfsv3_procid[NFS_NPROCS] = { 11278064Sume NFSPROC_NULL, 11378064Sume NFSPROC_GETATTR, 11478064Sume NFSPROC_SETATTR, 11578064Sume NFSPROC_NOOP, 11678064Sume NFSPROC_LOOKUP, 11778064Sume NFSPROC_READLINK, 11878064Sume NFSPROC_READ, 11978064Sume NFSPROC_NOOP, 12078064Sume NFSPROC_WRITE, 12178064Sume NFSPROC_CREATE, 12278064Sume NFSPROC_REMOVE, 12378064Sume NFSPROC_RENAME, 124148385Sume NFSPROC_LINK, 125148385Sume NFSPROC_SYMLINK, 12678064Sume NFSPROC_MKDIR, 12753541Sshin NFSPROC_RMDIR, 12878064Sume NFSPROC_READDIR, 12978064Sume NFSPROC_FSSTAT, 130165118Sbz NFSPROC_NOOP, 131165118Sbz NFSPROC_NOOP, 13278064Sume NFSPROC_NOOP, 13353541Sshin NFSPROC_NOOP, 13453541Sshin NFSPROC_NOOP, 13553541Sshin}; 136148987Sume 137120941Sume/* 13895023Ssuz * and the reverse mapping from generic to Version 2 procedure numbers 139120941Sume */ 140120941Sumeint nfsrvv2_procid[NFS_NPROCS] = { 141120941Sume NFSV2PROC_NULL, 14295023Ssuz NFSV2PROC_GETATTR, 14353541Sshin NFSV2PROC_SETATTR, 14478064Sume NFSV2PROC_LOOKUP, 145120941Sume NFSV2PROC_NOOP, 14653541Sshin NFSV2PROC_READLINK, 14753541Sshin NFSV2PROC_READ, 14853541Sshin NFSV2PROC_WRITE, 14953541Sshin NFSV2PROC_CREATE, 15053541Sshin NFSV2PROC_MKDIR, 15178064Sume NFSV2PROC_SYMLINK, 15253541Sshin NFSV2PROC_CREATE, 15353541Sshin NFSV2PROC_REMOVE, 15453541Sshin NFSV2PROC_RMDIR, 15553541Sshin NFSV2PROC_RENAME, 15653541Sshin NFSV2PROC_LINK, 15753541Sshin NFSV2PROC_READDIR, 15878064Sume NFSV2PROC_NOOP, 15978064Sume NFSV2PROC_STATFS, 16078064Sume NFSV2PROC_NOOP, 16178064Sume NFSV2PROC_NOOP, 16253541Sshin NFSV2PROC_NOOP, 16353541Sshin NFSV2PROC_NOOP, 16453541Sshin}; 16595023Ssuz 16653541Sshin/* 16753541Sshin * Maps errno values to nfs error numbers. 168120941Sume * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not 16953541Sshin * specifically defined in RFC 1094. 17078064Sume */ 17178064Sumestatic u_char nfsrv_v2errmap[ELAST] = { 17253541Sshin NFSERR_PERM, NFSERR_NOENT, 0, 0, 0, 17353541Sshin NFSERR_NXIO, 0, 0, 0, 0, 17453541Sshin 0, 0, NFSERR_ACCES, 0, 0, 17553541Sshin 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR, 17653541Sshin NFSERR_ISDIR, 0, 0, 0, 0, 17753541Sshin 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS, 17853541Sshin 0, 0, 0, 0, 0, 17953541Sshin 0, 0, 0, 0, 0, 18053541Sshin 0, 0, 0, 0, 0, 18153541Sshin 0, 0, 0, 0, 0, 18253541Sshin 0, 0, 0, 0, 0, 18353541Sshin 0, 0, 0, 0, 0, 18453541Sshin 0, 0, NFSERR_NAMETOL, 0, 0, 18553541Sshin NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE, 18653541Sshin 0 18753541Sshin}; 18853541Sshin 18953541Sshin/* 19053541Sshin * Maps errno values to nfs error numbers. 19153541Sshin * Although it is not obvious whether or not NFS clients really care if 19253541Sshin * a returned error value is in the specified list for the procedure, the 19353541Sshin * safest thing to do is filter them appropriately. For Version 2, the 19453541Sshin * X/Open XNFS document is the only specification that defines error values 19553541Sshin * for each RPC (The RFC simply lists all possible error values for all RPCs), 19653541Sshin * so I have decided to not do this for Version 2. 197142215Sglebius * The first entry is the default error return and the rest are the valid 198142215Sglebius * errors for that RPC in increasing numeric order. 199142215Sglebius */ 200151465Ssuzstatic short nfsv3err_null[] = { 201142215Sglebius 0, 202142215Sglebius 0, 20353541Sshin}; 204142215Sglebius 20553541Sshinstatic short nfsv3err_getattr[] = { 20653541Sshin NFSERR_IO, 207151465Ssuz NFSERR_IO, 20853541Sshin NFSERR_STALE, 20953541Sshin NFSERR_BADHANDLE, 210121765Ssam NFSERR_SERVERFAULT, 21153541Sshin 0, 21253541Sshin}; 21353541Sshin 21453541Sshinstatic short nfsv3err_setattr[] = { 21553541Sshin NFSERR_IO, 21653541Sshin NFSERR_PERM, 21753541Sshin NFSERR_IO, 218121765Ssam NFSERR_ACCES, 219121765Ssam NFSERR_INVAL, 220121765Ssam NFSERR_NOSPC, 221121765Ssam NFSERR_ROFS, 222121765Ssam NFSERR_DQUOT, 22353541Sshin NFSERR_STALE, 22462587Sitojun NFSERR_BADHANDLE, 22553541Sshin NFSERR_NOT_SYNC, 22662587Sitojun NFSERR_SERVERFAULT, 22762587Sitojun 0, 22862587Sitojun}; 22953541Sshin 23062587Sitojunstatic short nfsv3err_lookup[] = { 23162587Sitojun NFSERR_IO, 23253541Sshin NFSERR_NOENT, 23353541Sshin NFSERR_IO, 234151479Ssuz NFSERR_ACCES, 23553541Sshin NFSERR_NOTDIR, 23678064Sume NFSERR_NAMETOL, 23753541Sshin NFSERR_STALE, 23853541Sshin NFSERR_BADHANDLE, 23953541Sshin NFSERR_SERVERFAULT, 24062587Sitojun 0, 24153541Sshin}; 24253541Sshin 24353541Sshinstatic short nfsv3err_access[] = { 24453541Sshin NFSERR_IO, 24553541Sshin NFSERR_IO, 24662587Sitojun NFSERR_STALE, 24753541Sshin NFSERR_BADHANDLE, 24853541Sshin NFSERR_SERVERFAULT, 249120941Sume 0, 25053541Sshin}; 251165118Sbz 252120941Sumestatic short nfsv3err_readlink[] = { 25378064Sume NFSERR_IO, 25453541Sshin NFSERR_IO, 25553541Sshin NFSERR_ACCES, 25653541Sshin NFSERR_INVAL, 257120941Sume NFSERR_STALE, 258165118Sbz NFSERR_BADHANDLE, 25962587Sitojun NFSERR_NOTSUPP, 26053541Sshin NFSERR_SERVERFAULT, 26153541Sshin 0, 26253541Sshin}; 26353541Sshin 26453541Sshinstatic short nfsv3err_read[] = { 26553541Sshin NFSERR_IO, 26653541Sshin NFSERR_IO, 26753541Sshin NFSERR_NXIO, 26853541Sshin NFSERR_ACCES, 26953541Sshin NFSERR_INVAL, 27053541Sshin NFSERR_STALE, 27153541Sshin NFSERR_BADHANDLE, 27253541Sshin NFSERR_SERVERFAULT, 27353541Sshin 0, 27453541Sshin}; 27553541Sshin 27653541Sshinstatic short nfsv3err_write[] = { 277148987Sume NFSERR_IO, 27853541Sshin NFSERR_IO, 27953541Sshin NFSERR_ACCES, 28053541Sshin NFSERR_INVAL, 28153541Sshin NFSERR_FBIG, 28253541Sshin NFSERR_NOSPC, 28353541Sshin NFSERR_ROFS, 28453541Sshin NFSERR_DQUOT, 28562587Sitojun NFSERR_STALE, 28653541Sshin NFSERR_BADHANDLE, 28753541Sshin NFSERR_SERVERFAULT, 28853541Sshin 0, 28953541Sshin}; 29053541Sshin 29153541Sshinstatic short nfsv3err_create[] = { 29253541Sshin NFSERR_IO, 29353541Sshin NFSERR_IO, 29453541Sshin NFSERR_ACCES, 29553541Sshin NFSERR_EXIST, 29653541Sshin NFSERR_NOTDIR, 297148385Sume NFSERR_NOSPC, 298148385Sume NFSERR_ROFS, 299148385Sume NFSERR_NAMETOL, 300148385Sume NFSERR_DQUOT, 301148385Sume NFSERR_STALE, 302148385Sume NFSERR_BADHANDLE, 303120941Sume NFSERR_NOTSUPP, 304120941Sume NFSERR_SERVERFAULT, 305120941Sume 0, 30662587Sitojun}; 30753541Sshin 30853541Sshinstatic short nfsv3err_mkdir[] = { 309120941Sume NFSERR_IO, 310120941Sume NFSERR_IO, 31153541Sshin NFSERR_ACCES, 31253541Sshin NFSERR_EXIST, 313120941Sume NFSERR_NOTDIR, 314120941Sume NFSERR_NOSPC, 315120941Sume NFSERR_ROFS, 31662587Sitojun NFSERR_NAMETOL, 31762587Sitojun NFSERR_DQUOT, 31853541Sshin NFSERR_STALE, 31953541Sshin NFSERR_BADHANDLE, 32053541Sshin NFSERR_NOTSUPP, 321165118Sbz NFSERR_SERVERFAULT, 322165118Sbz 0, 323165118Sbz}; 324165118Sbz 325165118Sbzstatic short nfsv3err_symlink[] = { 326165118Sbz NFSERR_IO, 32778064Sume NFSERR_IO, 32862587Sitojun NFSERR_ACCES, 32953541Sshin NFSERR_EXIST, 33053541Sshin NFSERR_NOTDIR, 33153541Sshin NFSERR_NOSPC, 332108470Sschweikh NFSERR_ROFS, 33353541Sshin NFSERR_NAMETOL, 33453541Sshin NFSERR_DQUOT, 33553541Sshin NFSERR_STALE, 33653541Sshin NFSERR_BADHANDLE, 33753541Sshin NFSERR_NOTSUPP, 338148987Sume NFSERR_SERVERFAULT, 33953541Sshin 0, 34053541Sshin}; 34153541Sshin 34253541Sshinstatic short nfsv3err_mknod[] = { 34378064Sume NFSERR_IO, 34453541Sshin NFSERR_IO, 345148987Sume NFSERR_ACCES, 34653541Sshin NFSERR_EXIST, 34753541Sshin NFSERR_NOTDIR, 34853541Sshin NFSERR_NOSPC, 34953541Sshin NFSERR_ROFS, 350148385Sume NFSERR_NAMETOL, 35153541Sshin NFSERR_DQUOT, 35253541Sshin NFSERR_STALE, 35362587Sitojun NFSERR_BADHANDLE, 35453541Sshin NFSERR_NOTSUPP, 355148385Sume NFSERR_SERVERFAULT, 356120941Sume NFSERR_BADTYPE, 357148385Sume 0, 358148385Sume}; 35953541Sshin 36053541Sshinstatic short nfsv3err_remove[] = { 36153541Sshin NFSERR_IO, 36262587Sitojun NFSERR_NOENT, 36362587Sitojun NFSERR_IO, 36462587Sitojun NFSERR_ACCES, 36562587Sitojun NFSERR_NOTDIR, 36662587Sitojun NFSERR_ROFS, 36762587Sitojun NFSERR_NAMETOL, 36862587Sitojun NFSERR_STALE, 36962587Sitojun NFSERR_BADHANDLE, 37053541Sshin NFSERR_SERVERFAULT, 37162587Sitojun 0, 37253541Sshin}; 373111119Simp 37462587Sitojunstatic short nfsv3err_rmdir[] = { 375111119Simp NFSERR_IO, 37662587Sitojun NFSERR_NOENT, 37762587Sitojun NFSERR_IO, 37862587Sitojun NFSERR_ACCES, 37962587Sitojun NFSERR_EXIST, 38062587Sitojun NFSERR_NOTDIR, 38162587Sitojun NFSERR_INVAL, 38262587Sitojun NFSERR_ROFS, 38378064Sume NFSERR_NAMETOL, 38462587Sitojun NFSERR_NOTEMPTY, 38553541Sshin NFSERR_STALE, 38653541Sshin NFSERR_BADHANDLE, 38753541Sshin NFSERR_NOTSUPP, 38853541Sshin NFSERR_SERVERFAULT, 38953541Sshin 0, 39053541Sshin}; 39153541Sshin 39253541Sshinstatic short nfsv3err_rename[] = { 39353541Sshin NFSERR_IO, 39495023Ssuz NFSERR_NOENT, 39553541Sshin NFSERR_IO, 39653541Sshin NFSERR_ACCES, 39753541Sshin NFSERR_EXIST, 39853541Sshin NFSERR_XDEV, 39962587Sitojun NFSERR_NOTDIR, 40062587Sitojun NFSERR_ISDIR, 40153541Sshin NFSERR_INVAL, 40253541Sshin NFSERR_NOSPC, 40353541Sshin NFSERR_ROFS, 40453541Sshin NFSERR_MLINK, 40553541Sshin NFSERR_NAMETOL, 40653541Sshin NFSERR_NOTEMPTY, 40753541Sshin NFSERR_DQUOT, 408148385Sume NFSERR_STALE, 40953541Sshin NFSERR_BADHANDLE, 41053541Sshin NFSERR_NOTSUPP, 41153541Sshin NFSERR_SERVERFAULT, 41253541Sshin 0, 413148385Sume}; 414148385Sume 41553541Sshinstatic short nfsv3err_link[] = { 41653541Sshin NFSERR_IO, 41753541Sshin NFSERR_IO, 41853541Sshin NFSERR_ACCES, 41953541Sshin NFSERR_EXIST, 42053541Sshin NFSERR_XDEV, 42153541Sshin NFSERR_NOTDIR, 42253541Sshin NFSERR_INVAL, 42353541Sshin NFSERR_NOSPC, 42453541Sshin NFSERR_ROFS, 42553541Sshin NFSERR_MLINK, 42653541Sshin NFSERR_NAMETOL, 42753541Sshin NFSERR_DQUOT, 42853541Sshin NFSERR_STALE, 42953541Sshin NFSERR_BADHANDLE, 430148385Sume NFSERR_NOTSUPP, 43153541Sshin NFSERR_SERVERFAULT, 43295023Ssuz 0, 433148385Sume}; 43453541Sshin 43553541Sshinstatic short nfsv3err_readdir[] = { 436148987Sume NFSERR_IO, 437148987Sume NFSERR_IO, 438148987Sume NFSERR_ACCES, 439148987Sume NFSERR_NOTDIR, 44053541Sshin NFSERR_STALE, 44153541Sshin NFSERR_BADHANDLE, 44253541Sshin NFSERR_BAD_COOKIE, 443148385Sume NFSERR_TOOSMALL, 44453541Sshin NFSERR_SERVERFAULT, 445148385Sume 0, 446148385Sume}; 447148385Sume 448148385Sumestatic short nfsv3err_readdirplus[] = { 44953541Sshin NFSERR_IO, 450148385Sume NFSERR_IO, 451148385Sume NFSERR_ACCES, 452148385Sume NFSERR_NOTDIR, 453148385Sume NFSERR_STALE, 454148385Sume NFSERR_BADHANDLE, 455148385Sume NFSERR_BAD_COOKIE, 456148385Sume NFSERR_NOTSUPP, 457148385Sume NFSERR_TOOSMALL, 458148385Sume NFSERR_SERVERFAULT, 459148385Sume 0, 460148385Sume}; 461165118Sbz 462148385Sumestatic short nfsv3err_fsstat[] = { 463148385Sume NFSERR_IO, 464148385Sume NFSERR_IO, 465165118Sbz NFSERR_STALE, 466165118Sbz NFSERR_BADHANDLE, 467148385Sume NFSERR_SERVERFAULT, 46853541Sshin 0, 46953541Sshin}; 47053541Sshin 47153541Sshinstatic short nfsv3err_fsinfo[] = { 47253541Sshin NFSERR_STALE, 47353541Sshin NFSERR_STALE, 474148385Sume NFSERR_BADHANDLE, 475148385Sume NFSERR_SERVERFAULT, 476148385Sume 0, 47753541Sshin}; 478148385Sume 479148385Sumestatic short nfsv3err_pathconf[] = { 48053541Sshin NFSERR_STALE, 481148385Sume NFSERR_STALE, 48253541Sshin NFSERR_BADHANDLE, 48353541Sshin NFSERR_SERVERFAULT, 48453541Sshin 0, 48553541Sshin}; 48653541Sshin 487121315Sumestatic short nfsv3err_commit[] = { 48853541Sshin NFSERR_IO, 48953541Sshin NFSERR_IO, 49053541Sshin NFSERR_STALE, 49153541Sshin NFSERR_BADHANDLE, 49253541Sshin NFSERR_SERVERFAULT, 49353541Sshin 0, 49453541Sshin}; 49553541Sshin 49653541Sshinstatic short *nfsrv_v3errmap[] = { 49753541Sshin nfsv3err_null, 49853541Sshin nfsv3err_getattr, 49953541Sshin nfsv3err_setattr, 50053541Sshin nfsv3err_lookup, 50153541Sshin nfsv3err_access, 50253541Sshin nfsv3err_readlink, 50353541Sshin nfsv3err_read, 50453541Sshin nfsv3err_write, 50553541Sshin nfsv3err_create, 506120941Sume nfsv3err_mkdir, 50753541Sshin nfsv3err_symlink, 50853541Sshin nfsv3err_mknod, 50953541Sshin nfsv3err_remove, 51053541Sshin nfsv3err_rmdir, 51153541Sshin nfsv3err_rename, 51253541Sshin nfsv3err_link, 51353541Sshin nfsv3err_readdir, 51453541Sshin nfsv3err_readdirplus, 51553541Sshin nfsv3err_fsstat, 51653541Sshin nfsv3err_fsinfo, 51753541Sshin nfsv3err_pathconf, 518120941Sume nfsv3err_commit, 519120941Sume}; 52053541Sshin 521151536Ssuz/* 522148385Sume * Called once to initialize data structures... 523148385Sume */ 524148385Sumestatic int 525148385Sumenfsrv_modevent(module_t mod, int type, void *data) 526148385Sume{ 527148385Sume 52853541Sshin switch (type) { 529148385Sume case MOD_LOAD: 530148385Sume nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 531148385Sume nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 532148385Sume nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 533148385Sume nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 534148385Sume nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 535148385Sume nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 536148385Sume nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 53753541Sshin nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 53853541Sshin nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 53953541Sshin nfsrv_nfs_true = txdr_unsigned(TRUE); 54053541Sshin nfsrv_nfs_false = txdr_unsigned(FALSE); 54153541Sshin nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 54253541Sshin nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 543148987Sume if (nfsrv_ticks < 1) 54462587Sitojun nfsrv_ticks = 1; 54562587Sitojun 54662587Sitojun nfsrv_init(0); /* Init server data structures */ 54762587Sitojun nfsrv_initcache(); /* Init the server request cache */ 54853541Sshin 54953541Sshin nfsrv_timer(0); 55053541Sshin 55153541Sshin nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 55253541Sshin sysent[SYS_nfssvc].sy_narg = 2; 55353541Sshin nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 55453541Sshin sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 55553541Sshin break; 55662587Sitojun 55753541Sshin case MOD_UNLOAD: 55862587Sitojun 55962587Sitojun untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle); 56062587Sitojun sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 56162587Sitojun sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 56262587Sitojun break; 56353541Sshin } 56453541Sshin return 0; 56553541Sshin} 56653541Sshinstatic moduledata_t nfsserver_mod = { 56753541Sshin "nfsserver", 56853541Sshin nfsrv_modevent, 56953541Sshin NULL, 570165118Sbz}; 57153541SshinDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 57253541Sshin 57378064Sume/* So that loader and kldload(2) can find us, wherever we are.. */ 57478064SumeMODULE_VERSION(nfsserver, 1); 575165118Sbz 576165118Sbz/* 57778064Sume * Set up nameidata for a lookup() call and do it. 57862587Sitojun * 57962587Sitojun * If pubflag is set, this call is done for a lookup operation on the 58062587Sitojun * public filehandle. In that case we allow crossing mountpoints and 58162587Sitojun * absolute pathnames. However, the caller is expected to check that 58262587Sitojun * the lookup result is within the public fs, and deny access if 58362587Sitojun * it is not. 58462587Sitojun * 58562587Sitojun * nfs_namei() clears out garbage fields that namei() might leave garbage. 58662587Sitojun * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 58753541Sshin * error occurs but the parent was not requested. 58853541Sshin * 58962587Sitojun * dirp may be set whether an error is returned or not, and must be 590148385Sume * released by the caller. 59162587Sitojun */ 59262587Sitojunint 59362587Sitojunnfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 59462587Sitojun struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 59553541Sshin caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag) 596148385Sume{ 597148385Sume int i, rem; 598150202Ssuz struct mbuf *md; 59953541Sshin char *fromcp, *tocp, *cp; 60053541Sshin struct iovec aiov; 60178064Sume struct uio auio; 60253541Sshin struct vnode *dp; 603165118Sbz int error, rdonly, linklen; 60478064Sume struct componentname *cnp = &ndp->ni_cnd; 60553541Sshin 60653541Sshin *retdirp = NULL; 60753541Sshin cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 60878064Sume 60978064Sume /* 61078064Sume * Copy the name from the mbuf list to ndp->ni_pnbuf 61153541Sshin * and set the various ndp fields appropriately. 61253541Sshin */ 61353541Sshin fromcp = *dposp; 61453541Sshin tocp = cnp->cn_pnbuf; 61553541Sshin md = *mdp; 61678064Sume rem = mtod(md, caddr_t) + md->m_len - fromcp; 61778064Sume for (i = 0; i < len; i++) { 61878064Sume while (rem == 0) { 61962587Sitojun md = md->m_next; 62053541Sshin if (md == NULL) { 62153541Sshin error = EBADRPC; 62253541Sshin goto out; 62353541Sshin } 62453541Sshin fromcp = mtod(md, caddr_t); 62553541Sshin rem = md->m_len; 62653541Sshin } 62753541Sshin if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 62853541Sshin error = EACCES; 62953541Sshin goto out; 63053541Sshin } 63153541Sshin *tocp++ = *fromcp++; 63253541Sshin rem--; 63353541Sshin } 63453541Sshin *tocp = '\0'; 63553541Sshin *mdp = md; 63653541Sshin *dposp = fromcp; 63753541Sshin len = nfsm_rndup(len)-len; 63853541Sshin if (len > 0) { 63953541Sshin if (rem >= len) 64053541Sshin *dposp += len; 64162587Sitojun else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 64253541Sshin goto out; 64353541Sshin } 64495023Ssuz 64553541Sshin /* 64653541Sshin * Extract and set starting directory. 64753541Sshin */ 648165118Sbz error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 64962587Sitojun nam, &rdonly, pubflag); 65053541Sshin if (error) 65153541Sshin goto out; 65253541Sshin if (dp->v_type != VDIR) { 653120941Sume vrele(dp); 654165118Sbz error = ENOTDIR; 655120941Sume goto out; 65678064Sume } 65753541Sshin 65853541Sshin if (rdonly) 65953541Sshin cnp->cn_flags |= RDONLY; 660120941Sume 661120941Sume /* 66253541Sshin * Set return directory. Reference to dp is implicitly transfered 66353541Sshin * to the returned pointer 66453541Sshin */ 66553541Sshin *retdirp = dp; 66653541Sshin 66762587Sitojun if (pubflag) { 66853541Sshin /* 66953541Sshin * Oh joy. For WebNFS, handle those pesky '%' escapes, 67053541Sshin * and the 'native path' indicator. 67153541Sshin */ 67253541Sshin cp = uma_zalloc(namei_zone, M_WAITOK); 67353541Sshin fromcp = cnp->cn_pnbuf; 674151465Ssuz tocp = cp; 67562587Sitojun if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 67653541Sshin switch ((unsigned char)*fromcp) { 67753541Sshin case WEBNFS_NATIVE_CHAR: 67853541Sshin /* 67953541Sshin * 'Native' path for us is the same 68053541Sshin * as a path according to the NFS spec, 68153541Sshin * just skip the escape char. 68253541Sshin */ 68353541Sshin fromcp++; 68462587Sitojun break; 685151539Ssuz /* 686151539Ssuz * More may be added in the future, range 0x80-0xff 687151539Ssuz */ 688120941Sume default: 68978064Sume error = EIO; 69053541Sshin uma_zfree(namei_zone, cp); 691151539Ssuz goto out; 69278064Sume } 69378064Sume } 69478064Sume /* 69578064Sume * Translate the '%' escapes, URL-style. 69678064Sume */ 69778064Sume while (*fromcp != '\0') { 69878064Sume if (*fromcp == WEBNFS_ESC_CHAR) { 69978064Sume if (fromcp[1] != '\0' && fromcp[2] != '\0') { 70078064Sume fromcp++; 70153541Sshin *tocp++ = HEXSTRTOI(fromcp); 70253541Sshin fromcp += 2; 70353541Sshin continue; 70453541Sshin } else { 70553541Sshin error = ENOENT; 70653541Sshin uma_zfree(namei_zone, cp); 707151465Ssuz goto out; 70853541Sshin } 70953541Sshin } else 71053541Sshin *tocp++ = *fromcp++; 71153541Sshin } 71253541Sshin *tocp = '\0'; 71353541Sshin uma_zfree(namei_zone, cnp->cn_pnbuf); 71453541Sshin cnp->cn_pnbuf = cp; 71553541Sshin } 71653541Sshin 71753541Sshin ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 71853541Sshin ndp->ni_segflg = UIO_SYSSPACE; 71953541Sshin 72053541Sshin if (pubflag) { 72153541Sshin ndp->ni_rootdir = rootvnode; 72253541Sshin ndp->ni_loopcnt = 0; 72353541Sshin if (cnp->cn_pnbuf[0] == '/') 72453541Sshin dp = rootvnode; 72553541Sshin } else { 72653541Sshin cnp->cn_flags |= NOCROSSMOUNT; 72753541Sshin } 72853541Sshin 72953541Sshin /* 73053541Sshin * Initialize for scan, set ni_startdir and bump ref on dp again 73153541Sshin * becuase lookup() will dereference ni_startdir. 73253541Sshin */ 73353541Sshin 73453541Sshin cnp->cn_thread = td; 73553541Sshin VREF(dp); 73653541Sshin ndp->ni_startdir = dp; 73753541Sshin 738151539Ssuz for (;;) { 73953541Sshin cnp->cn_nameptr = cnp->cn_pnbuf; 74053541Sshin /* 74153541Sshin * Call lookup() to do the real work. If an error occurs, 74253541Sshin * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 74378064Sume * we do not have to dereference anything before returning. 74453541Sshin * In either case ni_startdir will be dereferenced and NULLed 745151539Ssuz * out. 74678064Sume */ 74762587Sitojun error = lookup(ndp); 74853541Sshin if (error) 749151465Ssuz break; 750151465Ssuz 75153541Sshin /* 75253541Sshin * Check for encountering a symbolic link. Trivial 75353541Sshin * termination occurs if no symlink encountered. 754151465Ssuz * Note: zfree is safe because error is 0, so we will 75553541Sshin * not zfree it again when we break. 75653541Sshin */ 75753541Sshin if ((cnp->cn_flags & ISSYMLINK) == 0) { 75853541Sshin nfsrv_object_create(ndp->ni_vp); 75953541Sshin if (cnp->cn_flags & (SAVENAME | SAVESTART)) 76053541Sshin cnp->cn_flags |= HASBUF; 76153541Sshin else 76253541Sshin uma_zfree(namei_zone, cnp->cn_pnbuf); 76353541Sshin break; 76453541Sshin } 76553541Sshin 76662587Sitojun /* 767151539Ssuz * Validate symlink 768151539Ssuz */ 769151539Ssuz if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 77053541Sshin VOP_UNLOCK(ndp->ni_dvp, 0, td); 77153541Sshin if (!pubflag) { 772151465Ssuz error = EINVAL; 77353541Sshin goto badlink2; 774151539Ssuz } 775151539Ssuz 77678064Sume if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 77753541Sshin error = ELOOP; 77853541Sshin goto badlink2; 77953541Sshin } 78053541Sshin if (ndp->ni_pathlen > 1) 78153541Sshin cp = uma_zalloc(namei_zone, M_WAITOK); 78253541Sshin else 78353541Sshin cp = cnp->cn_pnbuf; 78453541Sshin aiov.iov_base = cp; 78553541Sshin aiov.iov_len = MAXPATHLEN; 78653541Sshin auio.uio_iov = &aiov; 78753541Sshin auio.uio_iovcnt = 1; 78853541Sshin auio.uio_offset = 0; 78953541Sshin auio.uio_rw = UIO_READ; 79053541Sshin auio.uio_segflg = UIO_SYSSPACE; 79195023Ssuz auio.uio_td = NULL; 79295023Ssuz auio.uio_resid = MAXPATHLEN; 79395023Ssuz error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 79495023Ssuz if (error) { 79595023Ssuz badlink1: 796120941Sume if (ndp->ni_pathlen > 1) 79795023Ssuz uma_zfree(namei_zone, cp); 79853541Sshin badlink2: 799128422Sluigi vrele(ndp->ni_dvp); 80053541Sshin vput(ndp->ni_vp); 80153541Sshin break; 802151539Ssuz } 80353541Sshin linklen = MAXPATHLEN - auio.uio_resid; 80453541Sshin if (linklen == 0) { 80553541Sshin error = ENOENT; 80653541Sshin goto badlink1; 80753541Sshin } 80853541Sshin if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 80953541Sshin error = ENAMETOOLONG; 810128422Sluigi goto badlink1; 81153541Sshin } 81253541Sshin 81353541Sshin /* 81453541Sshin * Adjust or replace path 81553541Sshin */ 81653541Sshin if (ndp->ni_pathlen > 1) { 81753541Sshin bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 81853541Sshin uma_zfree(namei_zone, cnp->cn_pnbuf); 819151539Ssuz cnp->cn_pnbuf = cp; 820151539Ssuz } else 821151539Ssuz cnp->cn_pnbuf[linklen] = '\0'; 822151539Ssuz ndp->ni_pathlen += linklen; 823151539Ssuz 824151539Ssuz /* 825151539Ssuz * Cleanup refs for next loop and check if root directory 826151539Ssuz * should replace current directory. Normally ni_dvp 827151539Ssuz * becomes the new base directory and is cleaned up when 828151539Ssuz * we loop. Explicitly null pointers after invalidation 829151539Ssuz * to clarify operation. 830151539Ssuz */ 831151539Ssuz vput(ndp->ni_vp); 832151539Ssuz ndp->ni_vp = NULL; 833151539Ssuz 834151539Ssuz if (cnp->cn_pnbuf[0] == '/') { 835151539Ssuz vrele(ndp->ni_dvp); 836151539Ssuz ndp->ni_dvp = ndp->ni_rootdir; 837151539Ssuz VREF(ndp->ni_dvp); 838120941Sume } 83953541Sshin ndp->ni_startdir = ndp->ni_dvp; 84062587Sitojun ndp->ni_dvp = NULL; 84162587Sitojun } 84262587Sitojun 84378064Sume /* 84478064Sume * nfs_namei() guarentees that fields will not contain garbage 84578064Sume * whether an error occurs or not. This allows the caller to track 84678064Sume * cleanup state trivially. 84778064Sume */ 84853541Sshinout: 84953541Sshin if (error) { 85053541Sshin uma_zfree(namei_zone, cnp->cn_pnbuf); 85153541Sshin ndp->ni_vp = NULL; 85253541Sshin ndp->ni_dvp = NULL; 85353541Sshin ndp->ni_startdir = NULL; 85453541Sshin cnp->cn_flags &= ~HASBUF; 85562587Sitojun } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 85662587Sitojun ndp->ni_dvp = NULL; 85762587Sitojun } 85853541Sshin return (error); 85953541Sshin} 860148385Sume 86153541Sshin/* 862148385Sume * A fiddled version of m_adj() that ensures null fill to a long 86353541Sshin * boundary and only trims off the back end 86462587Sitojun */ 86562587Sitojunvoid 86653541Sshinnfsm_adj(struct mbuf *mp, int len, int nul) 86753541Sshin{ 86853541Sshin struct mbuf *m; 86953541Sshin int count, i; 87053541Sshin char *cp; 871148385Sume 872148385Sume /* 873148385Sume * Trim from tail. Scan the mbuf chain, 87492733Speter * calculating its length and finding the last mbuf. 875148385Sume * If the adjustment only affects this mbuf, then just 87662587Sitojun * adjust and return. Otherwise, rescan and truncate 877148385Sume * after the remaining size. 878148385Sume */ 879148385Sume count = 0; 880148385Sume m = mp; 88162587Sitojun for (;;) { 88262587Sitojun count += m->m_len; 88362587Sitojun if (m->m_next == NULL) 88462587Sitojun break; 88562587Sitojun m = m->m_next; 88662587Sitojun } 88762587Sitojun if (m->m_len > len) { 88862587Sitojun m->m_len -= len; 88953541Sshin if (nul > 0) { 89062587Sitojun cp = mtod(m, caddr_t)+m->m_len-nul; 89153541Sshin for (i = 0; i < nul; i++) 892111119Simp *cp++ = '\0'; 89362587Sitojun } 894111119Simp return; 89562587Sitojun } 89662587Sitojun count -= len; 89762587Sitojun if (count < 0) 89862587Sitojun count = 0; 89962587Sitojun /* 90062587Sitojun * Correct length for chain is "count". 90162587Sitojun * Find the mbuf with last data, adjust its length, 90278064Sume * and toss data from remaining mbufs on chain. 90362587Sitojun */ 904148385Sume for (m = mp; m; m = m->m_next) { 90553541Sshin if (m->m_len >= count) { 90653541Sshin m->m_len = count; 90753541Sshin if (nul > 0) { 90853541Sshin cp = mtod(m, caddr_t)+m->m_len-nul; 90953541Sshin for (i = 0; i < nul; i++) 91053541Sshin *cp++ = '\0'; 91153541Sshin } 91253541Sshin break; 91395023Ssuz } 91453541Sshin count -= m->m_len; 91553541Sshin } 91653541Sshin for (m = m->m_next;m;m = m->m_next) 91753541Sshin m->m_len = 0; 91862587Sitojun} 91962587Sitojun 92053541Sshin/* 92153541Sshin * Make these functions instead of macros, so that the kernel text size 922148385Sume * doesn't get too big... 92353541Sshin */ 924153227Sumevoid 925153227Sumenfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 926153227Sume struct vattr *before_vap, int after_ret, struct vattr *after_vap, 927153227Sume struct mbuf **mbp, char **bposp) 928153227Sume{ 929148385Sume struct mbuf *mb = *mbp; 930148385Sume char *bpos = *bposp; 931148385Sume u_int32_t *tl; 93253541Sshin 933148385Sume if (before_ret) { 934148385Sume tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 935148385Sume *tl = nfsrv_nfs_false; 936148385Sume } else { 937148385Sume tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 938148385Sume *tl++ = nfsrv_nfs_true; 93953541Sshin txdr_hyper(before_vap->va_size, tl); 94053541Sshin tl += 2; 94153541Sshin txdr_nfsv3time(&(before_vap->va_mtime), tl); 94253541Sshin tl += 2; 943148385Sume txdr_nfsv3time(&(before_vap->va_ctime), tl); 944148385Sume } 945148385Sume *bposp = bpos; 946165118Sbz *mbp = mb; 947148385Sume nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 948148385Sume} 949165118Sbz 950148385Sumevoid 95153541Sshinnfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 952148385Sume struct vattr *after_vap, struct mbuf **mbp, char **bposp) 95353541Sshin{ 95453541Sshin struct mbuf *mb = *mbp; 95553541Sshin char *bpos = *bposp; 95653541Sshin u_int32_t *tl; 957121315Sume struct nfs_fattr *fp; 95853541Sshin 95953541Sshin if (after_ret) { 96053541Sshin tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 96153541Sshin *tl = nfsrv_nfs_false; 96253541Sshin } else { 96353541Sshin tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 96453541Sshin *tl++ = nfsrv_nfs_true; 96562587Sitojun fp = (struct nfs_fattr *)tl; 96662587Sitojun nfsm_srvfattr(nfsd, after_vap, fp); 96762587Sitojun } 96862587Sitojun *mbp = mb; 96962587Sitojun *bposp = bpos; 97062587Sitojun} 971142215Sglebius 972142215Sglebiusvoid 973142215Sglebiusnfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 974142215Sglebius struct nfs_fattr *fp) 975142215Sglebius{ 976142215Sglebius 977142215Sglebius fp->fa_nlink = txdr_unsigned(vap->va_nlink); 97862587Sitojun fp->fa_uid = txdr_unsigned(vap->va_uid); 979142215Sglebius fp->fa_gid = txdr_unsigned(vap->va_gid); 980142215Sglebius if (nfsd->nd_flag & ND_NFSV3) { 98162587Sitojun fp->fa_type = vtonfsv3_type(vap->va_type); 98262587Sitojun fp->fa_mode = vtonfsv3_mode(vap->va_mode); 98362587Sitojun txdr_hyper(vap->va_size, &fp->fa3_size); 98462587Sitojun txdr_hyper(vap->va_bytes, &fp->fa3_used); 98562587Sitojun fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 98662587Sitojun fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 98762587Sitojun fp->fa3_fsid.nfsuquad[0] = 0; 98853541Sshin fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 98953541Sshin fp->fa3_fileid.nfsuquad[0] = 0; 990120941Sume fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 99153541Sshin txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 99253541Sshin txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 99353541Sshin txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 99453541Sshin } else { 99553541Sshin fp->fa_type = vtonfsv2_type(vap->va_type); 99653541Sshin fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 99753541Sshin fp->fa2_size = txdr_unsigned(vap->va_size); 99853541Sshin fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 99953541Sshin if (vap->va_type == VFIFO) 100053541Sshin fp->fa2_rdev = 0xffffffff; 100153541Sshin else 100253541Sshin fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 100353541Sshin fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 100453541Sshin fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 100553541Sshin fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 100653541Sshin txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 100753541Sshin txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1008120941Sume txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 100953541Sshin } 1010148385Sume} 1011148385Sume 1012148385Sume/* 1013148385Sume * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1014148385Sume * - look up fsid in mount list (if not found ret error) 1015148385Sume * - get vp and export rights by calling VFS_FHTOVP() 1016148385Sume * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 101753541Sshin * - if not lockflag unlock it with VOP_UNLOCK() 1018148385Sume */ 1019148385Sumeint 1020148385Sumenfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 1021148385Sume struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 1022148385Sume int *rdonlyp, int pubflag) 1023148385Sume{ 1024148385Sume struct thread *td = curthread; /* XXX */ 1025148385Sume struct mount *mp; 102653541Sshin int i; 102753541Sshin struct ucred *credanon; 102853541Sshin int error, exflags; 102953541Sshin#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 103053541Sshin struct sockaddr_int *saddr; 103153541Sshin#endif 103253541Sshin 103353541Sshin *vpp = NULL; 103453541Sshin 103553541Sshin if (nfs_ispublicfh(fhp)) { 103678064Sume if (!pubflag || !nfs_pub.np_valid) 103778468Ssumikawa return (ESTALE); 103878468Ssumikawa fhp = &nfs_pub.np_handle; 103978468Ssumikawa } 104078064Sume 104178064Sume mp = vfs_getvfs(&fhp->fh_fsid); 104278064Sume if (!mp) 1043142215Sglebius return (ESTALE); 1044142215Sglebius error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1045142215Sglebius if (error) 1046149829Sthompsa return (error); 1047120049Smdodd error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1048147306Sbrooks if (error) 104953541Sshin return (error); 105053541Sshin#ifdef MNT_EXNORESPORT 105153541Sshin if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 105253541Sshin saddr = (struct sockaddr_in *)nam; 105353541Sshin if ((saddr->sin_family == AF_INET || 105460938Sjake saddr->sin_family == AF_INET6) && 105553541Sshin /* same code for INET and INET6: sin*_port at same offet */ 105660938Sjake ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 105753541Sshin vput(*vpp); 105853541Sshin *vpp = NULL; 105962587Sitojun return (NFSERR_AUTHERR | AUTH_TOOWEAK); 106053541Sshin } 106153541Sshin } 106253541Sshin#endif 106378064Sume /* 106453541Sshin * Check/setup credentials. 106553541Sshin */ 106653541Sshin if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 106778064Sume cred->cr_uid = credanon->cr_uid; 106853541Sshin for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 106953541Sshin cred->cr_groups[i] = credanon->cr_groups[i]; 107053541Sshin cred->cr_ngroups = i; 107153541Sshin } 107253541Sshin if (exflags & MNT_EXRDONLY) 107353541Sshin *rdonlyp = 1; 107453541Sshin else 107562587Sitojun *rdonlyp = 0; 107653541Sshin 107753541Sshin nfsrv_object_create(*vpp); 107853541Sshin 107953541Sshin if (!lockflag) 108053541Sshin VOP_UNLOCK(*vpp, 0, td); 108153541Sshin return (0); 108278064Sume} 108378064Sume 108478064Sume 108578064Sume/* 108678064Sume * WebNFS: check if a filehandle is a public filehandle. For v3, this 108778064Sume * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 108878064Sume * transformed this to all zeroes in both cases, so check for it. 108978064Sume */ 109078064Sumeint 109178064Sumenfs_ispublicfh(fhandle_t *fhp) 109278064Sume{ 109378064Sume char *cp = (char *)fhp; 109478064Sume int i; 109578064Sume 109678064Sume for (i = 0; i < NFSX_V3FH; i++) 109778064Sume if (*cp++ != 0) 109878064Sume return (FALSE); 109978064Sume return (TRUE); 110053541Sshin} 1101148987Sume 110253541Sshin/* 110353541Sshin * This function compares two net addresses by family and returns TRUE 1104151539Ssuz * if they are the same host. 110553541Sshin * If there is any doubt, return FALSE. 1106151539Ssuz * The AF_INET family is handled as a special case so that address mbufs 110753541Sshin * don't need to be saved to store "struct in_addr", which is only 4 bytes. 110853541Sshin */ 110953541Sshinint 1110165118Sbznetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 111153541Sshin{ 111253541Sshin struct sockaddr_in *inetaddr; 111353541Sshin 111453541Sshin switch (family) { 111553541Sshin case AF_INET: 111653541Sshin inetaddr = (struct sockaddr_in *)nam; 111753541Sshin if (inetaddr->sin_family == AF_INET && 111853541Sshin inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 111953541Sshin return (1); 112053541Sshin break; 112153541Sshin#ifdef INET6 112253541Sshin case AF_INET6: 112353541Sshin { 112462587Sitojun register struct sockaddr_in6 *inet6addr1, *inet6addr2; 112562587Sitojun 112653541Sshin inet6addr1 = (struct sockaddr_in6 *)nam; 1127165118Sbz inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 112853541Sshin /* XXX - should test sin6_scope_id ? */ 112953541Sshin if (inet6addr1->sin6_family == AF_INET6 && 113053541Sshin IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 113153541Sshin &inet6addr2->sin6_addr)) 113253541Sshin return (1); 113353541Sshin break; 113453541Sshin } 113553541Sshin#endif 113653541Sshin default: 113753541Sshin break; 113853541Sshin }; 1139151465Ssuz return (0); 114053541Sshin} 1141120941Sume 114253541Sshin/* 1143120941Sume * Map errnos to NFS error numbers. For Version 3 also filter out error 114453541Sshin * numbers not specified for the associated procedure. 114553541Sshin */ 114653541Sshinint 114753541Sshinnfsrv_errmap(struct nfsrv_descript *nd, int err) 114853541Sshin{ 114953541Sshin short *defaulterrp, *errp; 115053541Sshin int e; 115162587Sitojun 115253541Sshin if (nd->nd_flag & ND_NFSV3) { 1153165118Sbz if (nd->nd_procnum <= NFSPROC_COMMIT) { 115453541Sshin errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 115553541Sshin while (*++errp) { 115653541Sshin if (*errp == err) 115753541Sshin return (err); 115878064Sume else if (*errp > err) 115953541Sshin break; 116053541Sshin } 116178064Sume return ((int)*defaulterrp); 1162165118Sbz } else 116353541Sshin return (err & 0xffff); 116453541Sshin } 116553541Sshin e = 0; 116653541Sshin if (err <= ELAST) 116753541Sshin e = nfsrv_v2errmap[err - 1]; 116853541Sshin if (e != 0) 116953541Sshin return (e); 117053541Sshin return (NFSERR_IO); 117195023Ssuz} 117253541Sshin 117353541Sshinint 117462587Sitojunnfsrv_object_create(struct vnode *vp) 1175151539Ssuz{ 117662587Sitojun 1177121161Sume if (vp == NULL || vp->v_type != VREG) 1178151539Ssuz return (1); 117953541Sshin return (vfs_object_create(vp, curthread, curthread->td_ucred)); 1180151539Ssuz} 118153541Sshin 118253541Sshin/* 118353541Sshin * Sort the group list in increasing numerical order. 118478064Sume * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 118578064Sume * that used to be here.) 118678064Sume */ 118778064Sumevoid 118878064Sumenfsrvw_sort(gid_t *list, int num) 118978064Sume{ 119078064Sume int i, j; 119178064Sume gid_t v; 119278064Sume 119378064Sume /* Insertion sort. */ 119478064Sume for (i = 1; i < num; i++) { 119578064Sume v = list[i]; 119678064Sume /* find correct slot for value v, moving others up */ 119778064Sume for (j = i; --j >= 0 && v < list[j];) 119878064Sume list[j + 1] = list[j]; 119978064Sume list[j + 1] = v; 120078064Sume } 120178064Sume} 120278064Sume 120378064Sume/* 120478064Sume * copy credentials making sure that the result can be compared with bcmp(). 120578064Sume */ 120678064Sumevoid 120778064Sumenfsrv_setcred(struct ucred *incred, struct ucred *outcred) 120878064Sume{ 120953541Sshin int i; 121053541Sshin 121153541Sshin bzero((caddr_t)outcred, sizeof (struct ucred)); 121253541Sshin outcred->cr_ref = 1; 121353541Sshin outcred->cr_uid = incred->cr_uid; 121453541Sshin outcred->cr_ngroups = incred->cr_ngroups; 121553541Sshin for (i = 0; i < incred->cr_ngroups; i++) 1216165118Sbz outcred->cr_groups[i] = incred->cr_groups[i]; 121753541Sshin nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 121895023Ssuz} 121953541Sshin 122053541Sshin/* 122153541Sshin * Helper functions for macros. 122262587Sitojun */ 122353541Sshin 122453541Sshinvoid 122553541Sshinnfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 122653541Sshin{ 122762587Sitojun u_int32_t *tl; 122853541Sshin 122953541Sshin if (v3) { 123053541Sshin tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 123162587Sitojun *tl++ = txdr_unsigned(NFSX_V3FH); 123253541Sshin bcopy(f, tl, NFSX_V3FH); 1233165118Sbz } else { 123453541Sshin tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 123553541Sshin bcopy(f, tl, NFSX_V2FH); 123653541Sshin } 123753541Sshin} 123862587Sitojun 123953541Sshinvoid 1240165118Sbznfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 124153541Sshin{ 124253541Sshin u_int32_t *tl; 124353541Sshin 124453541Sshin tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 124562587Sitojun *tl++ = nfsrv_nfs_true; 124662587Sitojun *tl++ = txdr_unsigned(NFSX_V3FH); 124778064Sume bcopy(f, tl, NFSX_V3FH); 1248120941Sume} 124962587Sitojun 125062587Sitojunint 125162587Sitojunnfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 125262587Sitojun{ 125362587Sitojun u_int32_t *tl; 125462587Sitojun 125562587Sitojun tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 125662587Sitojun if (tl == NULL) 125753541Sshin return EBADRPC; 125853541Sshin *s = fxdr_unsigned(int32_t, *tl); 125953541Sshin if (*s > m || *s <= 0) 126053541Sshin return EBADRPC; 126153541Sshin return 0; 126262587Sitojun} 1263120941Sume 1264151539Ssuzint 126553541Sshinnfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos) 126653541Sshin{ 126753541Sshin u_int32_t *tl; 126853541Sshin 126953541Sshin tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 127053541Sshin if (tl == NULL) 127153541Sshin return EBADRPC; 127253541Sshin *s = fxdr_unsigned(int32_t, *tl); 127353541Sshin if (*s > NFS_MAXNAMLEN) 127453541Sshin return NFSERR_NAMETOL; 127553541Sshin if (*s <= 0) 127653541Sshin return EBADRPC; 127753541Sshin return 0; 127853541Sshin} 127953541Sshin 128053541Sshinvoid 128153541Sshinnfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 128253541Sshin char **bp, char **be, caddr_t bpos) 128353541Sshin{ 128453541Sshin struct mbuf *nmp; 128553541Sshin 128653541Sshin if (*bp >= *be) { 128753541Sshin if (*mp == mb) 128853541Sshin (*mp)->m_len += *bp - bpos; 128953541Sshin MGET(nmp, M_TRYWAIT, MT_DATA); 129053541Sshin MCLGET(nmp, M_TRYWAIT); 129153541Sshin nmp->m_len = NFSMSIZ(nmp); 129253541Sshin (*mp)->m_next = nmp; 129353541Sshin *mp = nmp; 1294148987Sume *bp = mtod(*mp, caddr_t); 129553541Sshin *be = *bp + (*mp)->m_len; 129653541Sshin } 129753541Sshin *tl = (u_int32_t *)*bp; 129878064Sume} 129962587Sitojun 130062587Sitojunint 1301165118Sbznfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 130253541Sshin caddr_t *dpos) 130353541Sshin{ 130453541Sshin u_int32_t *tl; 130553541Sshin int fhlen; 130662587Sitojun 130753541Sshin if (nfsd->nd_flag & ND_NFSV3) { 130853541Sshin tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 130953541Sshin if (tl == NULL) 131053541Sshin return EBADRPC; 131153541Sshin fhlen = fxdr_unsigned(int, *tl); 131253541Sshin if (fhlen != 0 && fhlen != NFSX_V3FH) 131353541Sshin return EBADRPC; 131453541Sshin } else { 131553541Sshin fhlen = NFSX_V2FH; 131653541Sshin } 131753541Sshin if (fhlen != 0) { 131853541Sshin tl = nfsm_dissect_xx(fhlen, md, dpos); 1319151477Ssuz if (tl == NULL) 132053541Sshin return EBADRPC; 1321165118Sbz bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 132253541Sshin } else { 132353541Sshin bzero((caddr_t)(f), NFSX_V3FH); 132453541Sshin } 132562587Sitojun return 0; 132653541Sshin} 132753541Sshin 132853541Sshinint 132978064Sumenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 133078064Sume{ 1331165118Sbz u_int32_t *tl; 133278064Sume 133353541Sshin tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 133453541Sshin if (tl == NULL) 133553541Sshin return EBADRPC; 133653541Sshin if (*tl == nfsrv_nfs_true) { 1337148987Sume tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 133878064Sume if (tl == NULL) 133953541Sshin return EBADRPC; 1340151477Ssuz (a)->va_mode = nfstov_mode(*tl); 134162587Sitojun } 1342165118Sbz tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 134362587Sitojun if (tl == NULL) 1344151477Ssuz return EBADRPC; 134553541Sshin if (*tl == nfsrv_nfs_true) { 1346151477Ssuz tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1347151477Ssuz if (tl == NULL) 1348151477Ssuz return EBADRPC; 1349151477Ssuz (a)->va_uid = fxdr_unsigned(uid_t, *tl); 1350151477Ssuz } 1351151477Ssuz tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1352151477Ssuz if (tl == NULL) 1353151477Ssuz return EBADRPC; 1354151477Ssuz if (*tl == nfsrv_nfs_true) { 1355151477Ssuz tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1356151477Ssuz if (tl == NULL) 1357151477Ssuz return EBADRPC; 1358151477Ssuz (a)->va_gid = fxdr_unsigned(gid_t, *tl); 1359151477Ssuz } 1360151477Ssuz tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1361151477Ssuz if (tl == NULL) 1362151477Ssuz return EBADRPC; 1363151477Ssuz if (*tl == nfsrv_nfs_true) { 1364151477Ssuz tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 1365151477Ssuz if (tl == NULL) 1366151477Ssuz return EBADRPC; 1367151477Ssuz (a)->va_size = fxdr_hyper(tl); 1368151477Ssuz } 1369151477Ssuz tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1370151477Ssuz if (tl == NULL) 1371151477Ssuz return EBADRPC; 1372151477Ssuz switch (fxdr_unsigned(int, *tl)) { 1373151477Ssuz case NFSV3SATTRTIME_TOCLIENT: 1374151477Ssuz tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 1375151477Ssuz if (tl == NULL) 1376151477Ssuz return EBADRPC; 1377151477Ssuz fxdr_nfsv3time(tl, &(a)->va_atime); 1378151477Ssuz break; 1379151477Ssuz case NFSV3SATTRTIME_TOSERVER: 138053541Sshin getnanotime(&(a)->va_atime); 138153541Sshin break; 138253541Sshin } 138362587Sitojun tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 138453541Sshin if (tl == NULL) 138553541Sshin return EBADRPC; 138662587Sitojun switch (fxdr_unsigned(int, *tl)) { 138762587Sitojun case NFSV3SATTRTIME_TOCLIENT: 138862587Sitojun tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 138962587Sitojun if (tl == NULL) 139062587Sitojun return EBADRPC; 139162587Sitojun fxdr_nfsv3time(tl, &(a)->va_mtime); 139262587Sitojun break; 139362587Sitojun case NFSV3SATTRTIME_TOSERVER: 139462587Sitojun getnanotime(&(a)->va_mtime); 139562587Sitojun break; 139662587Sitojun } 139762587Sitojun return 0; 1398148887Srwatson} 139962587Sitojun