nfs_srvsubs.c revision 105481
1238730Sdelphij/* 2238730Sdelphij * Copyright (c) 1989, 1993 3238730Sdelphij * The Regents of the University of California. All rights reserved. 4238730Sdelphij * 5238730Sdelphij * This code is derived from software contributed to Berkeley by 6238730Sdelphij * Rick Macklem at The University of Guelph. 7238730Sdelphij * 8238730Sdelphij * Redistribution and use in source and binary forms, with or without 960786Sps * modification, are permitted provided that the following conditions 1060786Sps * are met: 1160786Sps * 1. Redistributions of source code must retain the above copyright 1260786Sps * notice, this list of conditions and the following disclaimer. 1360786Sps * 2. Redistributions in binary form must reproduce the above copyright 1460786Sps * notice, this list of conditions and the following disclaimer in the 1560786Sps * documentation and/or other materials provided with the distribution. 1660786Sps * 3. All advertising materials mentioning features or use of this software 1760786Sps * must display the following acknowledgement: 18161478Sdelphij * This product includes software developed by the University of 1960786Sps * California, Berkeley and its contributors. 20161478Sdelphij * 4. Neither the name of the University nor the names of its contributors 2189019Sps * may be used to endorse or promote products derived from this software 2289019Sps * without specific prior written permission. 2360786Sps * 24161478Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2560786Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2689019Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2789019Sps * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2889019Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29237613Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3060786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3160786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3260786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3360786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3460786Sps * SUCH DAMAGE. 35128345Stjr * 3660786Sps * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 3763128Sps * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 105481 2002-10-19 21:27:40Z rwatson $ 3860786Sps */ 3960786Sps 4060786Sps#include <sys/cdefs.h> 41161478Sdelphij__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 105481 2002-10-19 21:27:40Z rwatson $"); 4260786Sps 43161478Sdelphij/* 44161478Sdelphij * These functions support the macros and help fiddle mbuf chains for 4560786Sps * the nfs op functions. They do things like create the rpc header and 4660786Sps * copy data between mbuf chains and uio lists. 47161478Sdelphij */ 4860786Sps 4960786Sps#include "opt_inet6.h" 5060786Sps 5160786Sps#include <sys/param.h> 5260786Sps#include <sys/systm.h> 5363128Sps#include <sys/kernel.h> 5460786Sps#include <sys/bio.h> 5560786Sps#include <sys/buf.h> 5660786Sps#include <sys/proc.h> 5760786Sps#include <sys/mount.h> 5860786Sps#include <sys/vnode.h> 5960786Sps#include <sys/namei.h> 6060786Sps#include <sys/mbuf.h> 6163128Sps#include <sys/socket.h> 6263128Sps#include <sys/stat.h> 6360786Sps#include <sys/malloc.h> 64161478Sdelphij#include <sys/module.h> 65161478Sdelphij#include <sys/sysent.h> 66161478Sdelphij#include <sys/syscall.h> 67161478Sdelphij#include <sys/sysproto.h> 68161478Sdelphij 6960786Sps#include <vm/vm.h> 7060786Sps#include <vm/vm_object.h> 7160786Sps#include <vm/vm_extern.h> 7260786Sps#include <vm/uma.h> 7360786Sps 7460786Sps#include <nfs/rpcv2.h> 7560786Sps#include <nfs/nfsproto.h> 7660786Sps#include <nfsserver/nfs.h> 7760786Sps#include <nfs/xdr_subs.h> 78161478Sdelphij#include <nfsserver/nfsm_subs.h> 79161478Sdelphij 80161478Sdelphij#include <netinet/in.h> 81161478Sdelphij 82161478Sdelphij/* 8389019Sps * Data items converted to xdr at startup, since they are constant 8489019Sps * This is kinda hokey, but may save a little time doing byte swaps 8589019Sps */ 8660786Spsu_int32_t nfsrv_nfs_xdrneg1; 8760786Spsu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply, 8860786Sps nfsrv_rpc_msgdenied, nfsrv_rpc_autherr, 8989019Sps nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted; 9089019Spsu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false; 91161478Sdelphij 9289019Sps/* And other global data */ 9389019Spsstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 94161478Sdelphij NFNON, NFCHR, NFNON }; 95161478Sdelphij#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 96161478Sdelphij#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 97161478Sdelphij 98161478Sdelphijint nfsrv_ticks; 99161478Sdelphij 100161478Sdelphijstruct nfssvc_sockhead nfssvc_sockhead; 101161478Sdelphijint nfssvc_sockhead_flag; 10289019Spsstruct nfsd_head nfsd_head; 10389019Spsint nfsd_head_flag; 104161478Sdelphij 10589019Spsstatic int nfs_prev_nfssvc_sy_narg; 10689019Spsstatic sy_call_t *nfs_prev_nfssvc_sy_call; 10789019Sps 10889019Sps/* 10989019Sps * Mapping of old NFS Version 2 RPC numbers to generic numbers. 11089019Sps */ 11189019Spsint nfsrv_nfsv3_procid[NFS_NPROCS] = { 11289019Sps NFSPROC_NULL, 113161478Sdelphij NFSPROC_GETATTR, 114161478Sdelphij NFSPROC_SETATTR, 115161478Sdelphij NFSPROC_NOOP, 116161478Sdelphij NFSPROC_LOOKUP, 117161478Sdelphij NFSPROC_READLINK, 118161478Sdelphij NFSPROC_READ, 119161478Sdelphij NFSPROC_NOOP, 120161478Sdelphij NFSPROC_WRITE, 121161478Sdelphij NFSPROC_CREATE, 122161478Sdelphij NFSPROC_REMOVE, 123161478Sdelphij NFSPROC_RENAME, 124161478Sdelphij NFSPROC_LINK, 12589019Sps NFSPROC_SYMLINK, 12689019Sps NFSPROC_MKDIR, 127128345Stjr NFSPROC_RMDIR, 128128345Stjr NFSPROC_READDIR, 129161478Sdelphij NFSPROC_FSSTAT, 13089019Sps NFSPROC_NOOP, 13189019Sps NFSPROC_NOOP, 13289019Sps NFSPROC_NOOP, 13389019Sps NFSPROC_NOOP, 13489019Sps NFSPROC_NOOP, 13589019Sps}; 13689019Sps 137161478Sdelphij/* 138161478Sdelphij * and the reverse mapping from generic to Version 2 procedure numbers 139161478Sdelphij */ 140161478Sdelphijint nfsrvv2_procid[NFS_NPROCS] = { 141161478Sdelphij NFSV2PROC_NULL, 142161478Sdelphij NFSV2PROC_GETATTR, 143161478Sdelphij NFSV2PROC_SETATTR, 144161478Sdelphij NFSV2PROC_LOOKUP, 145161478Sdelphij NFSV2PROC_NOOP, 146161478Sdelphij NFSV2PROC_READLINK, 14760786Sps NFSV2PROC_READ, 14860786Sps NFSV2PROC_WRITE, 14960786Sps NFSV2PROC_CREATE, 15060786Sps NFSV2PROC_MKDIR, 15160786Sps NFSV2PROC_SYMLINK, 15260786Sps NFSV2PROC_CREATE, 15360786Sps NFSV2PROC_REMOVE, 154161478Sdelphij NFSV2PROC_RMDIR, 15560786Sps NFSV2PROC_RENAME, 156161478Sdelphij NFSV2PROC_LINK, 157161478Sdelphij NFSV2PROC_READDIR, 15860786Sps NFSV2PROC_NOOP, 15960786Sps NFSV2PROC_STATFS, 16063128Sps NFSV2PROC_NOOP, 161128345Stjr NFSV2PROC_NOOP, 162128345Stjr NFSV2PROC_NOOP, 16360786Sps NFSV2PROC_NOOP, 16460786Sps}; 16560786Sps 16660786Sps/* 16760786Sps * Maps errno values to nfs error numbers. 16860786Sps * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not 16960786Sps * specifically defined in RFC 1094. 17060786Sps */ 17160786Spsstatic u_char nfsrv_v2errmap[ELAST] = { 172128345Stjr NFSERR_PERM, NFSERR_NOENT, 0, 0, 0, 17360786Sps NFSERR_NXIO, 0, 0, 0, 0, 17460786Sps 0, 0, NFSERR_ACCES, 0, 0, 17563128Sps 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR, 17663128Sps NFSERR_ISDIR, 0, 0, 0, 0, 17763128Sps 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS, 17863128Sps 0, 0, 0, 0, 0, 17963128Sps 0, 0, 0, 0, 0, 18063128Sps 0, 0, 0, 0, 0, 18163128Sps 0, 0, 0, 0, 0, 18263128Sps 0, 0, 0, 0, 0, 18363128Sps 0, 0, 0, 0, 0, 18463128Sps 0, 0, NFSERR_NAMETOL, 0, 0, 185128345Stjr NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE, 18663128Sps 0 18763128Sps}; 18860786Sps 18963128Sps/* 19060786Sps * Maps errno values to nfs error numbers. 19163128Sps * Although it is not obvious whether or not NFS clients really care if 19263128Sps * a returned error value is in the specified list for the procedure, the 19363128Sps * safest thing to do is filter them appropriately. For Version 2, the 19463128Sps * X/Open XNFS document is the only specification that defines error values 19563128Sps * for each RPC (The RFC simply lists all possible error values for all RPCs), 196161478Sdelphij * so I have decided to not do this for Version 2. 19763128Sps * The first entry is the default error return and the rest are the valid 198161478Sdelphij * errors for that RPC in increasing numeric order. 19963128Sps */ 20063128Spsstatic short nfsv3err_null[] = { 20163128Sps 0, 20260786Sps 0, 20363128Sps}; 20463128Sps 20560786Spsstatic short nfsv3err_getattr[] = { 20663128Sps NFSERR_IO, 20763128Sps NFSERR_IO, 208128345Stjr NFSERR_STALE, 209128345Stjr NFSERR_BADHANDLE, 210128345Stjr NFSERR_SERVERFAULT, 211128345Stjr 0, 212128345Stjr}; 213128345Stjr 214128345Stjrstatic short nfsv3err_setattr[] = { 215128345Stjr NFSERR_IO, 216128345Stjr NFSERR_PERM, 217128345Stjr NFSERR_IO, 218128345Stjr NFSERR_ACCES, 219128345Stjr NFSERR_INVAL, 220128345Stjr NFSERR_NOSPC, 221128345Stjr NFSERR_ROFS, 22263128Sps NFSERR_DQUOT, 223128345Stjr NFSERR_STALE, 22460786Sps NFSERR_BADHANDLE, 22563128Sps NFSERR_NOT_SYNC, 22660786Sps NFSERR_SERVERFAULT, 22763128Sps 0, 22860786Sps}; 22960786Sps 23060786Spsstatic short nfsv3err_lookup[] = { 23160786Sps NFSERR_IO, 23263128Sps NFSERR_NOENT, 23360786Sps NFSERR_IO, 23460786Sps NFSERR_ACCES, 23560786Sps NFSERR_NOTDIR, 236161478Sdelphij NFSERR_NAMETOL, 237161478Sdelphij NFSERR_STALE, 23860786Sps NFSERR_BADHANDLE, 239161478Sdelphij NFSERR_SERVERFAULT, 240161478Sdelphij 0, 241161478Sdelphij}; 242161478Sdelphij 243161478Sdelphijstatic short nfsv3err_access[] = { 244161478Sdelphij NFSERR_IO, 245161478Sdelphij NFSERR_IO, 246161478Sdelphij NFSERR_STALE, 247161478Sdelphij NFSERR_BADHANDLE, 24889019Sps NFSERR_SERVERFAULT, 249161478Sdelphij 0, 250161478Sdelphij}; 251161478Sdelphij 25289019Spsstatic short nfsv3err_readlink[] = { 253161478Sdelphij NFSERR_IO, 254161478Sdelphij NFSERR_IO, 255161478Sdelphij NFSERR_ACCES, 256161478Sdelphij NFSERR_INVAL, 257161478Sdelphij NFSERR_STALE, 258161478Sdelphij NFSERR_BADHANDLE, 25989019Sps NFSERR_NOTSUPP, 260161478Sdelphij NFSERR_SERVERFAULT, 261161478Sdelphij 0, 26289019Sps}; 263161478Sdelphij 26489019Spsstatic short nfsv3err_read[] = { 265161478Sdelphij NFSERR_IO, 266172471Sdelphij NFSERR_IO, 26789019Sps NFSERR_NXIO, 268161478Sdelphij NFSERR_ACCES, 269161478Sdelphij NFSERR_INVAL, 270161478Sdelphij NFSERR_STALE, 271161478Sdelphij NFSERR_BADHANDLE, 272161478Sdelphij NFSERR_SERVERFAULT, 273161478Sdelphij 0, 274161478Sdelphij}; 275161478Sdelphij 276161478Sdelphijstatic short nfsv3err_write[] = { 277161478Sdelphij NFSERR_IO, 278161478Sdelphij NFSERR_IO, 279161478Sdelphij NFSERR_ACCES, 280161478Sdelphij NFSERR_INVAL, 281161478Sdelphij NFSERR_FBIG, 282161478Sdelphij NFSERR_NOSPC, 283161478Sdelphij NFSERR_ROFS, 284161478Sdelphij NFSERR_DQUOT, 285161478Sdelphij NFSERR_STALE, 286161478Sdelphij NFSERR_BADHANDLE, 287161478Sdelphij NFSERR_SERVERFAULT, 288161478Sdelphij 0, 289161478Sdelphij}; 290161478Sdelphij 291161478Sdelphijstatic short nfsv3err_create[] = { 292161478Sdelphij NFSERR_IO, 293161478Sdelphij NFSERR_IO, 294161478Sdelphij NFSERR_ACCES, 29589019Sps NFSERR_EXIST, 29689019Sps NFSERR_NOTDIR, 297161478Sdelphij NFSERR_NOSPC, 298161478Sdelphij NFSERR_ROFS, 299161478Sdelphij NFSERR_NAMETOL, 300161478Sdelphij NFSERR_DQUOT, 301161478Sdelphij NFSERR_STALE, 302161478Sdelphij NFSERR_BADHANDLE, 303161478Sdelphij NFSERR_NOTSUPP, 304161478Sdelphij NFSERR_SERVERFAULT, 305161478Sdelphij 0, 306161478Sdelphij}; 307161478Sdelphij 308161478Sdelphijstatic short nfsv3err_mkdir[] = { 309161478Sdelphij NFSERR_IO, 310161478Sdelphij NFSERR_IO, 311161478Sdelphij NFSERR_ACCES, 312161478Sdelphij NFSERR_EXIST, 313161478Sdelphij NFSERR_NOTDIR, 314161478Sdelphij NFSERR_NOSPC, 315161478Sdelphij NFSERR_ROFS, 316161478Sdelphij NFSERR_NAMETOL, 317161478Sdelphij NFSERR_DQUOT, 318161478Sdelphij NFSERR_STALE, 319161478Sdelphij NFSERR_BADHANDLE, 320161478Sdelphij NFSERR_NOTSUPP, 321161478Sdelphij NFSERR_SERVERFAULT, 322161478Sdelphij 0, 323161478Sdelphij}; 324161478Sdelphij 325161478Sdelphijstatic short nfsv3err_symlink[] = { 326161478Sdelphij NFSERR_IO, 327161478Sdelphij NFSERR_IO, 328161478Sdelphij NFSERR_ACCES, 329161478Sdelphij NFSERR_EXIST, 33089019Sps NFSERR_NOTDIR, 331161478Sdelphij NFSERR_NOSPC, 332161478Sdelphij NFSERR_ROFS, 333161478Sdelphij NFSERR_NAMETOL, 33489019Sps NFSERR_DQUOT, 33589019Sps NFSERR_STALE, 33689019Sps NFSERR_BADHANDLE, 337161478Sdelphij NFSERR_NOTSUPP, 338161478Sdelphij NFSERR_SERVERFAULT, 339161478Sdelphij 0, 340161478Sdelphij}; 341161478Sdelphij 342161478Sdelphijstatic short nfsv3err_mknod[] = { 34360786Sps NFSERR_IO, 344161478Sdelphij NFSERR_IO, 34560786Sps NFSERR_ACCES, 346161478Sdelphij NFSERR_EXIST, 347161478Sdelphij NFSERR_NOTDIR, 34860786Sps NFSERR_NOSPC, 349161478Sdelphij NFSERR_ROFS, 350161478Sdelphij NFSERR_NAMETOL, 351161478Sdelphij NFSERR_DQUOT, 35260786Sps NFSERR_STALE, 35360786Sps NFSERR_BADHANDLE, 35460786Sps NFSERR_NOTSUPP, 355161478Sdelphij NFSERR_SERVERFAULT, 35660786Sps NFSERR_BADTYPE, 357161478Sdelphij 0, 358161478Sdelphij}; 35960786Sps 360161478Sdelphijstatic short nfsv3err_remove[] = { 36160786Sps NFSERR_IO, 36260786Sps NFSERR_NOENT, 36360786Sps NFSERR_IO, 36460786Sps NFSERR_ACCES, 36560786Sps NFSERR_NOTDIR, 36660786Sps NFSERR_ROFS, 36760786Sps NFSERR_NAMETOL, 36860786Sps NFSERR_STALE, 36960786Sps NFSERR_BADHANDLE, 37060786Sps NFSERR_SERVERFAULT, 371161478Sdelphij 0, 372161478Sdelphij}; 373161478Sdelphij 374161478Sdelphijstatic short nfsv3err_rmdir[] = { 375161478Sdelphij NFSERR_IO, 376161478Sdelphij NFSERR_NOENT, 377161478Sdelphij NFSERR_IO, 378161478Sdelphij NFSERR_ACCES, 379161478Sdelphij NFSERR_EXIST, 380161478Sdelphij NFSERR_NOTDIR, 381161478Sdelphij NFSERR_INVAL, 382161478Sdelphij NFSERR_ROFS, 383161478Sdelphij NFSERR_NAMETOL, 384161478Sdelphij NFSERR_NOTEMPTY, 38560786Sps NFSERR_STALE, 38660786Sps NFSERR_BADHANDLE, 38760786Sps NFSERR_NOTSUPP, 38860786Sps NFSERR_SERVERFAULT, 38960786Sps 0, 39060786Sps}; 39160786Sps 39260786Spsstatic short nfsv3err_rename[] = { 39360786Sps NFSERR_IO, 39460786Sps NFSERR_NOENT, 395161478Sdelphij NFSERR_IO, 396161478Sdelphij NFSERR_ACCES, 397161478Sdelphij NFSERR_EXIST, 398161478Sdelphij NFSERR_XDEV, 399161478Sdelphij NFSERR_NOTDIR, 400161478Sdelphij NFSERR_ISDIR, 401161478Sdelphij NFSERR_INVAL, 402161478Sdelphij NFSERR_NOSPC, 403161478Sdelphij NFSERR_ROFS, 404161478Sdelphij NFSERR_MLINK, 405161478Sdelphij NFSERR_NAMETOL, 406161478Sdelphij NFSERR_NOTEMPTY, 407161478Sdelphij NFSERR_DQUOT, 408161478Sdelphij NFSERR_STALE, 40960786Sps NFSERR_BADHANDLE, 41060786Sps NFSERR_NOTSUPP, 41160786Sps NFSERR_SERVERFAULT, 41260786Sps 0, 41360786Sps}; 41460786Sps 41560786Spsstatic short nfsv3err_link[] = { 41660786Sps NFSERR_IO, 41760786Sps NFSERR_IO, 418161478Sdelphij NFSERR_ACCES, 419161478Sdelphij NFSERR_EXIST, 42060786Sps NFSERR_XDEV, 421161478Sdelphij NFSERR_NOTDIR, 42260786Sps NFSERR_INVAL, 423161478Sdelphij NFSERR_NOSPC, 42460786Sps NFSERR_ROFS, 425161478Sdelphij NFSERR_MLINK, 42660786Sps NFSERR_NAMETOL, 427161478Sdelphij NFSERR_DQUOT, 428161478Sdelphij NFSERR_STALE, 42960786Sps NFSERR_BADHANDLE, 430161478Sdelphij NFSERR_NOTSUPP, 43160786Sps NFSERR_SERVERFAULT, 432161478Sdelphij 0, 433161478Sdelphij}; 434161478Sdelphij 435161478Sdelphijstatic short nfsv3err_readdir[] = { 436161478Sdelphij NFSERR_IO, 437161478Sdelphij NFSERR_IO, 438161478Sdelphij NFSERR_ACCES, 439161478Sdelphij NFSERR_NOTDIR, 440161478Sdelphij NFSERR_STALE, 441161478Sdelphij NFSERR_BADHANDLE, 442161478Sdelphij NFSERR_BAD_COOKIE, 443161478Sdelphij NFSERR_TOOSMALL, 444161478Sdelphij NFSERR_SERVERFAULT, 445161478Sdelphij 0, 446161478Sdelphij}; 447161478Sdelphij 448161478Sdelphijstatic short nfsv3err_readdirplus[] = { 449161478Sdelphij NFSERR_IO, 450161478Sdelphij NFSERR_IO, 451161478Sdelphij NFSERR_ACCES, 452161478Sdelphij NFSERR_NOTDIR, 453161478Sdelphij NFSERR_STALE, 454161478Sdelphij NFSERR_BADHANDLE, 455161478Sdelphij NFSERR_BAD_COOKIE, 456161478Sdelphij NFSERR_NOTSUPP, 457161478Sdelphij NFSERR_TOOSMALL, 458161478Sdelphij NFSERR_SERVERFAULT, 459161478Sdelphij 0, 460161478Sdelphij}; 46160786Sps 46260786Spsstatic short nfsv3err_fsstat[] = { 463161478Sdelphij NFSERR_IO, 46460786Sps NFSERR_IO, 46560786Sps NFSERR_STALE, 46660786Sps NFSERR_BADHANDLE, 467161478Sdelphij NFSERR_SERVERFAULT, 468161478Sdelphij 0, 469161478Sdelphij}; 47060786Sps 471161478Sdelphijstatic short nfsv3err_fsinfo[] = { 472161478Sdelphij NFSERR_STALE, 47360786Sps NFSERR_STALE, 47460786Sps NFSERR_BADHANDLE, 47560786Sps NFSERR_SERVERFAULT, 47660786Sps 0, 47760786Sps}; 478161478Sdelphij 479161478Sdelphijstatic short nfsv3err_pathconf[] = { 48060786Sps NFSERR_STALE, 481161478Sdelphij NFSERR_STALE, 48260786Sps NFSERR_BADHANDLE, 48360786Sps NFSERR_SERVERFAULT, 484161478Sdelphij 0, 485161478Sdelphij}; 486161478Sdelphij 487161478Sdelphijstatic short nfsv3err_commit[] = { 488161478Sdelphij NFSERR_IO, 489161478Sdelphij NFSERR_IO, 490161478Sdelphij NFSERR_STALE, 491161478Sdelphij NFSERR_BADHANDLE, 492161478Sdelphij NFSERR_SERVERFAULT, 493161478Sdelphij 0, 494161478Sdelphij}; 495161478Sdelphij 496161478Sdelphijstatic short *nfsrv_v3errmap[] = { 497161478Sdelphij nfsv3err_null, 498161478Sdelphij nfsv3err_getattr, 499161478Sdelphij nfsv3err_setattr, 500161478Sdelphij nfsv3err_lookup, 501161478Sdelphij nfsv3err_access, 502161478Sdelphij nfsv3err_readlink, 503161478Sdelphij nfsv3err_read, 50460786Sps nfsv3err_write, 50560786Sps nfsv3err_create, 50660786Sps nfsv3err_mkdir, 50760786Sps nfsv3err_symlink, 50860786Sps nfsv3err_mknod, 50960786Sps nfsv3err_remove, 51060786Sps nfsv3err_rmdir, 51160786Sps nfsv3err_rename, 512161478Sdelphij nfsv3err_link, 51360786Sps nfsv3err_readdir, 51460786Sps nfsv3err_readdirplus, 51560786Sps nfsv3err_fsstat, 51660786Sps nfsv3err_fsinfo, 51760786Sps nfsv3err_pathconf, 518161478Sdelphij nfsv3err_commit, 51960786Sps}; 520161478Sdelphij 521172471Sdelphij/* 52260786Sps * Called once to initialize data structures... 523161478Sdelphij */ 52460786Spsstatic int 52560786Spsnfsrv_modevent(module_t mod, int type, void *data) 52660786Sps{ 52760786Sps 52860786Sps switch (type) { 52960786Sps case MOD_LOAD: 53089019Sps nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 53189019Sps nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 53289019Sps nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 533161478Sdelphij nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 534161478Sdelphij nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 53589019Sps nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 536161478Sdelphij nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 537161478Sdelphij nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 538161478Sdelphij nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 53989019Sps nfsrv_nfs_true = txdr_unsigned(TRUE); 54089019Sps nfsrv_nfs_false = txdr_unsigned(FALSE); 54189019Sps nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 542161478Sdelphij nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 543161478Sdelphij if (nfsrv_ticks < 1) 544161478Sdelphij nfsrv_ticks = 1; 545161478Sdelphij 546161478Sdelphij nfsrv_init(0); /* Init server data structures */ 547161478Sdelphij nfsrv_initcache(); /* Init the server request cache */ 548161478Sdelphij 549161478Sdelphij nfsrv_timer(0); 550161478Sdelphij 551161478Sdelphij nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 552161478Sdelphij sysent[SYS_nfssvc].sy_narg = 2; 553161478Sdelphij nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 554161478Sdelphij sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 555161478Sdelphij break; 55660786Sps 55760786Sps case MOD_UNLOAD: 558161478Sdelphij 559161478Sdelphij untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle); 560161478Sdelphij sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 561161478Sdelphij sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 56289019Sps break; 56360786Sps } 564161478Sdelphij return 0; 565161478Sdelphij} 56660786Spsstatic moduledata_t nfsserver_mod = { 567161478Sdelphij "nfsserver", 56860786Sps nfsrv_modevent, 56960786Sps NULL, 570161478Sdelphij}; 571161478SdelphijDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 572161478Sdelphij 57360786Sps/* So that loader and kldload(2) can find us, wherever we are.. */ 574161478SdelphijMODULE_VERSION(nfsserver, 1); 575161478Sdelphij 576161478Sdelphij/* 577161478Sdelphij * Set up nameidata for a lookup() call and do it. 57860786Sps * 57989019Sps * If pubflag is set, this call is done for a lookup operation on the 580161478Sdelphij * public filehandle. In that case we allow crossing mountpoints and 581161478Sdelphij * absolute pathnames. However, the caller is expected to check that 582161478Sdelphij * the lookup result is within the public fs, and deny access if 583161478Sdelphij * it is not. 584161478Sdelphij * 585161478Sdelphij * nfs_namei() clears out garbage fields that namei() might leave garbage. 586161478Sdelphij * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 587161478Sdelphij * error occurs but the parent was not requested. 588237613Sdelphij * 589237613Sdelphij * dirp may be set whether an error is returned or not, and must be 590237613Sdelphij * released by the caller. 591237613Sdelphij */ 592161478Sdelphijint 593237613Sdelphijnfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 594161478Sdelphij struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 59589019Sps caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag) 59660786Sps{ 597161478Sdelphij int i, rem; 59860786Sps struct mbuf *md; 599161478Sdelphij char *fromcp, *tocp, *cp; 600161478Sdelphij struct iovec aiov; 601161478Sdelphij struct uio auio; 602191930Sdelphij struct vnode *dp; 603191930Sdelphij int error, rdonly, linklen; 604191930Sdelphij struct componentname *cnp = &ndp->ni_cnd; 605191930Sdelphij 606191930Sdelphij *retdirp = NULL; 607191930Sdelphij cnp->cn_flags |= NOMACCHECK; 608161478Sdelphij cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 609161478Sdelphij 610161478Sdelphij /* 61160786Sps * Copy the name from the mbuf list to ndp->ni_pnbuf 612161478Sdelphij * and set the various ndp fields appropriately. 613172471Sdelphij */ 614161478Sdelphij fromcp = *dposp; 615161478Sdelphij tocp = cnp->cn_pnbuf; 616161478Sdelphij md = *mdp; 617161478Sdelphij rem = mtod(md, caddr_t) + md->m_len - fromcp; 61860786Sps for (i = 0; i < len; i++) { 619161478Sdelphij while (rem == 0) { 620161478Sdelphij md = md->m_next; 621161478Sdelphij if (md == NULL) { 622161478Sdelphij error = EBADRPC; 623161478Sdelphij goto out; 624161478Sdelphij } 62560786Sps fromcp = mtod(md, caddr_t); 62660786Sps rem = md->m_len; 62760786Sps } 62860786Sps if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 62960786Sps error = EACCES; 63060786Sps goto out; 631161478Sdelphij } 63289019Sps *tocp++ = *fromcp++; 633161478Sdelphij rem--; 634161478Sdelphij } 635161478Sdelphij *tocp = '\0'; 636161478Sdelphij *mdp = md; 637161478Sdelphij *dposp = fromcp; 638161478Sdelphij len = nfsm_rndup(len)-len; 639161478Sdelphij if (len > 0) { 640161478Sdelphij if (rem >= len) 641161478Sdelphij *dposp += len; 64260786Sps else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 64360786Sps goto out; 64489019Sps } 64560786Sps 64689019Sps /* 64789019Sps * Extract and set starting directory. 64889019Sps */ 64960786Sps error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 650161478Sdelphij nam, &rdonly, pubflag); 65160786Sps if (error) 652161478Sdelphij goto out; 653161478Sdelphij if (dp->v_type != VDIR) { 654161478Sdelphij vrele(dp); 65560786Sps error = ENOTDIR; 65660786Sps goto out; 65760786Sps } 65860786Sps 65960786Sps if (rdonly) 66060786Sps cnp->cn_flags |= RDONLY; 66189019Sps 66289019Sps /* 66389019Sps * Set return directory. Reference to dp is implicitly transfered 66489019Sps * to the returned pointer 66589019Sps */ 66689019Sps *retdirp = dp; 66789019Sps 66889019Sps if (pubflag) { 66989019Sps /* 67089019Sps * Oh joy. For WebNFS, handle those pesky '%' escapes, 67189019Sps * and the 'native path' indicator. 67289019Sps */ 67389019Sps cp = uma_zalloc(namei_zone, M_WAITOK); 67489019Sps fromcp = cnp->cn_pnbuf; 67589019Sps tocp = cp; 67689019Sps if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 67789019Sps switch ((unsigned char)*fromcp) { 67889019Sps case WEBNFS_NATIVE_CHAR: 67989019Sps /* 68089019Sps * 'Native' path for us is the same 68189019Sps * as a path according to the NFS spec, 68289019Sps * just skip the escape char. 68389019Sps */ 68489019Sps fromcp++; 68589019Sps break; 686161478Sdelphij /* 687161478Sdelphij * More may be added in the future, range 0x80-0xff 688161478Sdelphij */ 68989019Sps default: 690161478Sdelphij error = EIO; 69189019Sps uma_zfree(namei_zone, cp); 69289019Sps goto out; 69389019Sps } 69489019Sps } 695161478Sdelphij /* 696161478Sdelphij * Translate the '%' escapes, URL-style. 697161478Sdelphij */ 698161478Sdelphij while (*fromcp != '\0') { 699161478Sdelphij if (*fromcp == WEBNFS_ESC_CHAR) { 700161478Sdelphij if (fromcp[1] != '\0' && fromcp[2] != '\0') { 701161478Sdelphij fromcp++; 702161478Sdelphij *tocp++ = HEXSTRTOI(fromcp); 703161478Sdelphij fromcp += 2; 704161478Sdelphij continue; 705161478Sdelphij } else { 706161478Sdelphij error = ENOENT; 707161478Sdelphij uma_zfree(namei_zone, cp); 708161478Sdelphij goto out; 709161478Sdelphij } 710161478Sdelphij } else 711161478Sdelphij *tocp++ = *fromcp++; 712161478Sdelphij } 713161478Sdelphij *tocp = '\0'; 714161478Sdelphij uma_zfree(namei_zone, cnp->cn_pnbuf); 715161478Sdelphij cnp->cn_pnbuf = cp; 716161478Sdelphij } 717161478Sdelphij 718161478Sdelphij ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 719161478Sdelphij ndp->ni_segflg = UIO_SYSSPACE; 720161478Sdelphij 721161478Sdelphij if (pubflag) { 722161478Sdelphij ndp->ni_rootdir = rootvnode; 723161478Sdelphij ndp->ni_loopcnt = 0; 724161478Sdelphij if (cnp->cn_pnbuf[0] == '/') 725161478Sdelphij dp = rootvnode; 726161478Sdelphij } else { 727161478Sdelphij cnp->cn_flags |= NOCROSSMOUNT; 728161478Sdelphij } 729161478Sdelphij 730161478Sdelphij /* 731161478Sdelphij * Initialize for scan, set ni_startdir and bump ref on dp again 732161478Sdelphij * becuase lookup() will dereference ni_startdir. 733161478Sdelphij */ 734161478Sdelphij 735161478Sdelphij cnp->cn_thread = td; 736161478Sdelphij VREF(dp); 73789019Sps ndp->ni_startdir = dp; 73860786Sps 73960786Sps for (;;) { 74060786Sps cnp->cn_nameptr = cnp->cn_pnbuf; 74160786Sps /* 74260786Sps * Call lookup() to do the real work. If an error occurs, 74360786Sps * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 744161478Sdelphij * we do not have to dereference anything before returning. 74560786Sps * In either case ni_startdir will be dereferenced and NULLed 74660786Sps * out. 74760786Sps */ 74860786Sps error = lookup(ndp); 74960786Sps if (error) 75060786Sps break; 751161478Sdelphij 75260786Sps /* 75360786Sps * Check for encountering a symbolic link. Trivial 75460786Sps * termination occurs if no symlink encountered. 75560786Sps * Note: zfree is safe because error is 0, so we will 75660786Sps * not zfree it again when we break. 75760786Sps */ 75860786Sps if ((cnp->cn_flags & ISSYMLINK) == 0) { 75960786Sps nfsrv_object_create(ndp->ni_vp); 76060786Sps if (cnp->cn_flags & (SAVENAME | SAVESTART)) 76160786Sps cnp->cn_flags |= HASBUF; 762161478Sdelphij else 763161478Sdelphij uma_zfree(namei_zone, cnp->cn_pnbuf); 764161478Sdelphij break; 765161478Sdelphij } 766161478Sdelphij 767161478Sdelphij /* 768161478Sdelphij * Validate symlink 769161478Sdelphij */ 770161478Sdelphij if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 771161478Sdelphij VOP_UNLOCK(ndp->ni_dvp, 0, td); 77260786Sps if (!pubflag) { 77360786Sps error = EINVAL; 77460786Sps goto badlink2; 77560786Sps } 77660786Sps 77760786Sps if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 77860786Sps error = ELOOP; 77960786Sps goto badlink2; 78060786Sps } 78160786Sps if (ndp->ni_pathlen > 1) 782161478Sdelphij cp = uma_zalloc(namei_zone, M_WAITOK); 783161478Sdelphij else 784161478Sdelphij cp = cnp->cn_pnbuf; 785161478Sdelphij aiov.iov_base = cp; 786161478Sdelphij aiov.iov_len = MAXPATHLEN; 787161478Sdelphij auio.uio_iov = &aiov; 788161478Sdelphij auio.uio_iovcnt = 1; 789161478Sdelphij auio.uio_offset = 0; 790161478Sdelphij auio.uio_rw = UIO_READ; 791161478Sdelphij auio.uio_segflg = UIO_SYSSPACE; 792161478Sdelphij auio.uio_td = NULL; 793161478Sdelphij auio.uio_resid = MAXPATHLEN; 794161478Sdelphij error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 795161478Sdelphij if (error) { 796161478Sdelphij badlink1: 797161478Sdelphij if (ndp->ni_pathlen > 1) 798161478Sdelphij uma_zfree(namei_zone, cp); 799161478Sdelphij badlink2: 800161478Sdelphij vrele(ndp->ni_dvp); 801161478Sdelphij vput(ndp->ni_vp); 802161478Sdelphij break; 803161478Sdelphij } 804161478Sdelphij linklen = MAXPATHLEN - auio.uio_resid; 805161478Sdelphij if (linklen == 0) { 806161478Sdelphij error = ENOENT; 807161478Sdelphij goto badlink1; 808161478Sdelphij } 809161478Sdelphij if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 810161478Sdelphij error = ENAMETOOLONG; 811161478Sdelphij goto badlink1; 812161478Sdelphij } 813161478Sdelphij 814161478Sdelphij /* 815161478Sdelphij * Adjust or replace path 816161478Sdelphij */ 817161478Sdelphij if (ndp->ni_pathlen > 1) { 818161478Sdelphij bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 819161478Sdelphij uma_zfree(namei_zone, cnp->cn_pnbuf); 820161478Sdelphij cnp->cn_pnbuf = cp; 821161478Sdelphij } else 822161478Sdelphij cnp->cn_pnbuf[linklen] = '\0'; 823161478Sdelphij ndp->ni_pathlen += linklen; 824161478Sdelphij 825161478Sdelphij /* 82660786Sps * Cleanup refs for next loop and check if root directory 82760786Sps * should replace current directory. Normally ni_dvp 82860786Sps * becomes the new base directory and is cleaned up when 82960786Sps * we loop. Explicitly null pointers after invalidation 83060786Sps * to clarify operation. 83160786Sps */ 83260786Sps vput(ndp->ni_vp); 83389019Sps ndp->ni_vp = NULL; 83489019Sps 83560786Sps if (cnp->cn_pnbuf[0] == '/') { 83689019Sps vrele(ndp->ni_dvp); 837161478Sdelphij ndp->ni_dvp = ndp->ni_rootdir; 838161478Sdelphij VREF(ndp->ni_dvp); 839161478Sdelphij } 840161478Sdelphij ndp->ni_startdir = ndp->ni_dvp; 841161478Sdelphij ndp->ni_dvp = NULL; 84260786Sps } 84360786Sps 84460786Sps /* 84560786Sps * nfs_namei() guarentees that fields will not contain garbage 846161478Sdelphij * whether an error occurs or not. This allows the caller to track 847161478Sdelphij * cleanup state trivially. 848161478Sdelphij */ 84960786Spsout: 85060786Sps if (error) { 85160786Sps uma_zfree(namei_zone, cnp->cn_pnbuf); 852161478Sdelphij ndp->ni_vp = NULL; 85360786Sps ndp->ni_dvp = NULL; 854161478Sdelphij ndp->ni_startdir = NULL; 85560786Sps cnp->cn_flags &= ~HASBUF; 856161478Sdelphij } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 85760786Sps ndp->ni_dvp = NULL; 858161478Sdelphij } 85960786Sps return (error); 860161478Sdelphij} 861161478Sdelphij 862161478Sdelphij/* 863161478Sdelphij * A fiddled version of m_adj() that ensures null fill to a long 864161478Sdelphij * boundary and only trims off the back end 865161478Sdelphij */ 866161478Sdelphijvoid 867161478Sdelphijnfsm_adj(struct mbuf *mp, int len, int nul) 868161478Sdelphij{ 869161478Sdelphij struct mbuf *m; 870161478Sdelphij int count, i; 871161478Sdelphij char *cp; 872161478Sdelphij 873161478Sdelphij /* 874161478Sdelphij * Trim from tail. Scan the mbuf chain, 875161478Sdelphij * calculating its length and finding the last mbuf. 876161478Sdelphij * If the adjustment only affects this mbuf, then just 877161478Sdelphij * adjust and return. Otherwise, rescan and truncate 878161478Sdelphij * after the remaining size. 87960786Sps */ 88060786Sps count = 0; 88160786Sps m = mp; 88260786Sps for (;;) { 88360786Sps count += m->m_len; 88460786Sps if (m->m_next == NULL) 88560786Sps break; 88660786Sps m = m->m_next; 887161478Sdelphij } 888161478Sdelphij if (m->m_len > len) { 889161478Sdelphij m->m_len -= len; 890161478Sdelphij if (nul > 0) { 891161478Sdelphij cp = mtod(m, caddr_t)+m->m_len-nul; 89289019Sps for (i = 0; i < nul; i++) 893128345Stjr *cp++ = '\0'; 894128345Stjr } 895128345Stjr return; 896128345Stjr } 897128345Stjr count -= len; 898128345Stjr if (count < 0) 899128345Stjr count = 0; 900161478Sdelphij /* 90189019Sps * Correct length for chain is "count". 902161478Sdelphij * Find the mbuf with last data, adjust its length, 903161478Sdelphij * and toss data from remaining mbufs on chain. 904161478Sdelphij */ 905161478Sdelphij for (m = mp; m; m = m->m_next) { 906161478Sdelphij if (m->m_len >= count) { 907161478Sdelphij m->m_len = count; 908161478Sdelphij if (nul > 0) { 909161478Sdelphij cp = mtod(m, caddr_t)+m->m_len-nul; 910161478Sdelphij for (i = 0; i < nul; i++) 91189019Sps *cp++ = '\0'; 912161478Sdelphij } 913161478Sdelphij break; 914161478Sdelphij } 915161478Sdelphij count -= m->m_len; 916161478Sdelphij } 917161478Sdelphij for (m = m->m_next;m;m = m->m_next) 918161478Sdelphij m->m_len = 0; 919161478Sdelphij} 920161478Sdelphij 921161478Sdelphij/* 922161478Sdelphij * Make these functions instead of macros, so that the kernel text size 923161478Sdelphij * doesn't get too big... 924161478Sdelphij */ 925161478Sdelphijvoid 92660786Spsnfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 927161478Sdelphij struct vattr *before_vap, int after_ret, struct vattr *after_vap, 928161478Sdelphij struct mbuf **mbp, char **bposp) 929161478Sdelphij{ 930161478Sdelphij struct mbuf *mb = *mbp; 93160786Sps char *bpos = *bposp; 93260786Sps u_int32_t *tl; 93360786Sps 93460786Sps if (before_ret) { 93560786Sps tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 93660786Sps *tl = nfsrv_nfs_false; 93760786Sps } else { 93860786Sps tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 93960786Sps *tl++ = nfsrv_nfs_true; 94060786Sps txdr_hyper(before_vap->va_size, tl); 941161478Sdelphij tl += 2; 94260786Sps txdr_nfsv3time(&(before_vap->va_mtime), tl); 94360786Sps tl += 2; 944161478Sdelphij txdr_nfsv3time(&(before_vap->va_ctime), tl); 94560786Sps } 94660786Sps *bposp = bpos; 947172471Sdelphij *mbp = mb; 94860786Sps nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 94960786Sps} 95060786Sps 95160786Spsvoid 952161478Sdelphijnfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 95360786Sps struct vattr *after_vap, struct mbuf **mbp, char **bposp) 95460786Sps{ 955161478Sdelphij struct mbuf *mb = *mbp; 956161478Sdelphij char *bpos = *bposp; 957161478Sdelphij u_int32_t *tl; 958161478Sdelphij struct nfs_fattr *fp; 959161478Sdelphij 96060786Sps if (after_ret) { 961161478Sdelphij tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 96260786Sps *tl = nfsrv_nfs_false; 963161478Sdelphij } else { 964161478Sdelphij tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 965161478Sdelphij *tl++ = nfsrv_nfs_true; 966161478Sdelphij fp = (struct nfs_fattr *)tl; 967161478Sdelphij nfsm_srvfattr(nfsd, after_vap, fp); 968161478Sdelphij } 969161478Sdelphij *mbp = mb; 97060786Sps *bposp = bpos; 971161478Sdelphij} 97260786Sps 973161478Sdelphijvoid 974161478Sdelphijnfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 97560786Sps struct nfs_fattr *fp) 976161478Sdelphij{ 977161478Sdelphij 978161478Sdelphij fp->fa_nlink = txdr_unsigned(vap->va_nlink); 979161478Sdelphij fp->fa_uid = txdr_unsigned(vap->va_uid); 980161478Sdelphij fp->fa_gid = txdr_unsigned(vap->va_gid); 981161478Sdelphij if (nfsd->nd_flag & ND_NFSV3) { 982161478Sdelphij fp->fa_type = vtonfsv3_type(vap->va_type); 983161478Sdelphij fp->fa_mode = vtonfsv3_mode(vap->va_mode); 984161478Sdelphij txdr_hyper(vap->va_size, &fp->fa3_size); 985161478Sdelphij txdr_hyper(vap->va_bytes, &fp->fa3_used); 986161478Sdelphij fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 987161478Sdelphij fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 988161478Sdelphij fp->fa3_fsid.nfsuquad[0] = 0; 989161478Sdelphij fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 990161478Sdelphij fp->fa3_fileid.nfsuquad[0] = 0; 99160786Sps fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 99260786Sps txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 99360786Sps txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 99460786Sps txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 99560786Sps } else { 99660786Sps fp->fa_type = vtonfsv2_type(vap->va_type); 997195941Sdelphij fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 99860786Sps fp->fa2_size = txdr_unsigned(vap->va_size); 999195941Sdelphij fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 100060786Sps if (vap->va_type == VFIFO) 1001161478Sdelphij fp->fa2_rdev = 0xffffffff; 1002161478Sdelphij else 100360786Sps fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 100460786Sps fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 100560786Sps fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 100660786Sps fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 100760786Sps txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 100860786Sps txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1009161478Sdelphij txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 101060786Sps } 101160786Sps} 101260786Sps 101360786Sps/* 101460786Sps * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 101560786Sps * - look up fsid in mount list (if not found ret error) 101660786Sps * - get vp and export rights by calling VFS_FHTOVP() 1017161478Sdelphij * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1018161478Sdelphij * - if not lockflag unlock it with VOP_UNLOCK() 1019161478Sdelphij */ 1020161478Sdelphijint 1021161478Sdelphijnfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 1022161478Sdelphij struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 1023161478Sdelphij int *rdonlyp, int pubflag) 1024161478Sdelphij{ 1025161478Sdelphij struct thread *td = curthread; /* XXX */ 1026161478Sdelphij struct mount *mp; 1027161478Sdelphij int i; 102860786Sps struct ucred *credanon; 102960786Sps int error, exflags; 103060786Sps#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1031170259Sdelphij struct sockaddr_int *saddr; 1032170259Sdelphij#endif 1033170259Sdelphij 1034170259Sdelphij *vpp = NULL; 1035170259Sdelphij 1036170259Sdelphij if (nfs_ispublicfh(fhp)) { 1037170259Sdelphij if (!pubflag || !nfs_pub.np_valid) 1038170259Sdelphij return (ESTALE); 1039170259Sdelphij fhp = &nfs_pub.np_handle; 104060786Sps } 1041191930Sdelphij 104260786Sps mp = vfs_getvfs(&fhp->fh_fsid); 104360786Sps if (!mp) 104460786Sps return (ESTALE); 104560786Sps error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1046173685Sdelphij if (error) 1047195941Sdelphij return (error); 1048173685Sdelphij error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1049173685Sdelphij if (error) 1050191930Sdelphij return (error); 1051191930Sdelphij#ifdef MNT_EXNORESPORT 1052191930Sdelphij if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1053191930Sdelphij saddr = (struct sockaddr_in *)nam; 1054191930Sdelphij if ((saddr->sin_family == AF_INET || 1055191930Sdelphij saddr->sin_family == AF_INET6) && 1056195941Sdelphij /* same code for INET and INET6: sin*_port at same offet */ 1057195941Sdelphij ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1058195941Sdelphij vput(*vpp); 1059195941Sdelphij *vpp = NULL; 1060195941Sdelphij return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1061195941Sdelphij } 1062173685Sdelphij } 1063195941Sdelphij#endif 1064173685Sdelphij /* 1065173685Sdelphij * Check/setup credentials. 1066173685Sdelphij */ 106760786Sps if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 106860786Sps cred->cr_uid = credanon->cr_uid; 106960786Sps for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1070191930Sdelphij cred->cr_groups[i] = credanon->cr_groups[i]; 107189019Sps cred->cr_ngroups = i; 1072191930Sdelphij } 1073191930Sdelphij if (exflags & MNT_EXRDONLY) 1074191930Sdelphij *rdonlyp = 1; 1075191930Sdelphij else 1076191930Sdelphij *rdonlyp = 0; 1077191930Sdelphij 1078191930Sdelphij nfsrv_object_create(*vpp); 1079191930Sdelphij 1080191930Sdelphij if (!lockflag) 108160786Sps VOP_UNLOCK(*vpp, 0, td); 108260786Sps return (0); 108360786Sps} 108460786Sps 108560786Sps 108660786Sps/* 108760786Sps * WebNFS: check if a filehandle is a public filehandle. For v3, this 108860786Sps * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 108960786Sps * transformed this to all zeroes in both cases, so check for it. 109060786Sps */ 109160786Spsint 109260786Spsnfs_ispublicfh(fhandle_t *fhp) 109360786Sps{ 109460786Sps char *cp = (char *)fhp; 109560786Sps int i; 109660786Sps 109760786Sps for (i = 0; i < NFSX_V3FH; i++) 109860786Sps if (*cp++ != 0) 1099161478Sdelphij return (FALSE); 1100161478Sdelphij return (TRUE); 1101161478Sdelphij} 1102161478Sdelphij 1103161478Sdelphij/* 1104161478Sdelphij * This function compares two net addresses by family and returns TRUE 1105161478Sdelphij * if they are the same host. 1106161478Sdelphij * If there is any doubt, return FALSE. 1107161478Sdelphij * The AF_INET family is handled as a special case so that address mbufs 1108161478Sdelphij * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1109161478Sdelphij */ 1110161478Sdelphijint 111160786Spsnetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 111260786Sps{ 111360786Sps struct sockaddr_in *inetaddr; 1114161478Sdelphij 111560786Sps switch (family) { 111660786Sps case AF_INET: 111760786Sps inetaddr = (struct sockaddr_in *)nam; 111860786Sps if (inetaddr->sin_family == AF_INET && 111960786Sps inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 112060786Sps return (1); 112160786Sps break; 112260786Sps#ifdef INET6 112360786Sps case AF_INET6: 112460786Sps { 112560786Sps register struct sockaddr_in6 *inet6addr1, *inet6addr2; 112660786Sps 112760786Sps inet6addr1 = (struct sockaddr_in6 *)nam; 112860786Sps inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 112960786Sps /* XXX - should test sin6_scope_id ? */ 113060786Sps if (inet6addr1->sin6_family == AF_INET6 && 113160786Sps IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 113260786Sps &inet6addr2->sin6_addr)) 1133170259Sdelphij return (1); 113460786Sps break; 113560786Sps } 1136170259Sdelphij#endif 113760786Sps default: 113889019Sps break; 113960786Sps }; 114060786Sps return (0); 114160786Sps} 114260786Sps 114360786Sps/* 114460786Sps * Map errnos to NFS error numbers. For Version 3 also filter out error 114560786Sps * numbers not specified for the associated procedure. 114689019Sps */ 114760786Spsint 114860786Spsnfsrv_errmap(struct nfsrv_descript *nd, int err) 1149161478Sdelphij{ 115060786Sps short *defaulterrp, *errp; 115160786Sps int e; 115260786Sps 115360786Sps if (nd->nd_flag & ND_NFSV3) { 115489019Sps if (nd->nd_procnum <= NFSPROC_COMMIT) { 115560786Sps errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 115689019Sps while (*++errp) { 115789019Sps if (*errp == err) 115889019Sps return (err); 115989019Sps else if (*errp > err) 116089019Sps break; 116189019Sps } 116289019Sps return ((int)*defaulterrp); 116389019Sps } else 116489019Sps return (err & 0xffff); 116560786Sps } 116689019Sps e = 0; 116760786Sps if (err <= ELAST) 116860786Sps e = nfsrv_v2errmap[err - 1]; 116989019Sps if (e != 0) 117060786Sps return (e); 117160786Sps return (NFSERR_IO); 1172170259Sdelphij} 1173170259Sdelphij 117460786Spsint 117560786Spsnfsrv_object_create(struct vnode *vp) 117660786Sps{ 117760786Sps 117860786Sps if (vp == NULL || vp->v_type != VREG) 117960786Sps return (1); 118060786Sps return (vfs_object_create(vp, curthread, curthread->td_ucred)); 118160786Sps} 1182170259Sdelphij 118360786Sps/* 118460786Sps * Sort the group list in increasing numerical order. 1185170259Sdelphij * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 118660786Sps * that used to be here.) 118789019Sps */ 118860786Spsvoid 118960786Spsnfsrvw_sort(gid_t *list, int num) 119060786Sps{ 119160786Sps int i, j; 119260786Sps gid_t v; 119360786Sps 119460786Sps /* Insertion sort. */ 119589019Sps for (i = 1; i < num; i++) { 119689019Sps v = list[i]; 119760786Sps /* find correct slot for value v, moving others up */ 119860786Sps for (j = i; --j >= 0 && v < list[j];) 119960786Sps list[j + 1] = list[j]; 1200161478Sdelphij list[j + 1] = v; 120160786Sps } 120260786Sps} 120360786Sps 120460786Sps/* 120560786Sps * copy credentials making sure that the result can be compared with bcmp(). 120660786Sps */ 120760786Spsvoid 120860786Spsnfsrv_setcred(struct ucred *incred, struct ucred *outcred) 120960786Sps{ 121060786Sps int i; 121160786Sps 121260786Sps bzero((caddr_t)outcred, sizeof (struct ucred)); 121360786Sps outcred->cr_ref = 1; 121460786Sps outcred->cr_uid = incred->cr_uid; 121560786Sps outcred->cr_ngroups = incred->cr_ngroups; 121660786Sps for (i = 0; i < incred->cr_ngroups; i++) 121760786Sps outcred->cr_groups[i] = incred->cr_groups[i]; 121860786Sps nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 121989019Sps} 122060786Sps 122189019Sps/* 122289019Sps * Helper functions for macros. 122389019Sps */ 122489019Sps 122589019Spsvoid 122689019Spsnfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 122789019Sps{ 122889019Sps u_int32_t *tl; 122989019Sps 123089019Sps if (v3) { 123189019Sps tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 123289019Sps *tl++ = txdr_unsigned(NFSX_V3FH); 123360786Sps bcopy(f, tl, NFSX_V3FH); 123489019Sps } else { 123560786Sps tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 1236149487Stjr bcopy(f, tl, NFSX_V2FH); 1237149487Stjr } 123889019Sps} 123989019Sps 124089019Spsvoid 124160786Spsnfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 124289019Sps{ 124360786Sps u_int32_t *tl; 124460786Sps 124589019Sps tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1246170259Sdelphij *tl++ = nfsrv_nfs_true; 1247170259Sdelphij *tl++ = txdr_unsigned(NFSX_V3FH); 124860786Sps bcopy(f, tl, NFSX_V3FH); 124960786Sps} 1250 1251int 1252nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1253{ 1254 u_int32_t *tl; 1255 1256 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1257 if (tl == NULL) 1258 return EBADRPC; 1259 *s = fxdr_unsigned(int32_t, *tl); 1260 if (*s > m || *s <= 0) 1261 return EBADRPC; 1262 return 0; 1263} 1264 1265int 1266nfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos) 1267{ 1268 u_int32_t *tl; 1269 1270 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1271 if (tl == NULL) 1272 return EBADRPC; 1273 *s = fxdr_unsigned(int32_t, *tl); 1274 if (*s > NFS_MAXNAMLEN) 1275 return NFSERR_NAMETOL; 1276 if (*s <= 0) 1277 return EBADRPC; 1278 return 0; 1279} 1280 1281void 1282nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 1283 char **bp, char **be, caddr_t bpos) 1284{ 1285 struct mbuf *nmp; 1286 1287 if (*bp >= *be) { 1288 if (*mp == mb) 1289 (*mp)->m_len += *bp - bpos; 1290 MGET(nmp, M_TRYWAIT, MT_DATA); 1291 MCLGET(nmp, M_TRYWAIT); 1292 nmp->m_len = NFSMSIZ(nmp); 1293 (*mp)->m_next = nmp; 1294 *mp = nmp; 1295 *bp = mtod(*mp, caddr_t); 1296 *be = *bp + (*mp)->m_len; 1297 } 1298 *tl = (u_int32_t *)*bp; 1299} 1300 1301int 1302nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 1303 caddr_t *dpos) 1304{ 1305 u_int32_t *tl; 1306 int fhlen; 1307 1308 if (nfsd->nd_flag & ND_NFSV3) { 1309 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1310 if (tl == NULL) 1311 return EBADRPC; 1312 fhlen = fxdr_unsigned(int, *tl); 1313 if (fhlen != 0 && fhlen != NFSX_V3FH) 1314 return EBADRPC; 1315 } else { 1316 fhlen = NFSX_V2FH; 1317 } 1318 if (fhlen != 0) { 1319 tl = nfsm_dissect_xx(fhlen, md, dpos); 1320 if (tl == NULL) 1321 return EBADRPC; 1322 bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 1323 } else { 1324 bzero((caddr_t)(f), NFSX_V3FH); 1325 } 1326 return 0; 1327} 1328 1329int 1330nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 1331{ 1332 u_int32_t *tl; 1333 1334 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1335 if (tl == NULL) 1336 return EBADRPC; 1337 if (*tl == nfsrv_nfs_true) { 1338 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1339 if (tl == NULL) 1340 return EBADRPC; 1341 (a)->va_mode = nfstov_mode(*tl); 1342 } 1343 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1344 if (tl == NULL) 1345 return EBADRPC; 1346 if (*tl == nfsrv_nfs_true) { 1347 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1348 if (tl == NULL) 1349 return EBADRPC; 1350 (a)->va_uid = fxdr_unsigned(uid_t, *tl); 1351 } 1352 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1353 if (tl == NULL) 1354 return EBADRPC; 1355 if (*tl == nfsrv_nfs_true) { 1356 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1357 if (tl == NULL) 1358 return EBADRPC; 1359 (a)->va_gid = fxdr_unsigned(gid_t, *tl); 1360 } 1361 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1362 if (tl == NULL) 1363 return EBADRPC; 1364 if (*tl == nfsrv_nfs_true) { 1365 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 1366 if (tl == NULL) 1367 return EBADRPC; 1368 (a)->va_size = fxdr_hyper(tl); 1369 } 1370 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1371 if (tl == NULL) 1372 return EBADRPC; 1373 switch (fxdr_unsigned(int, *tl)) { 1374 case NFSV3SATTRTIME_TOCLIENT: 1375 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 1376 if (tl == NULL) 1377 return EBADRPC; 1378 fxdr_nfsv3time(tl, &(a)->va_atime); 1379 break; 1380 case NFSV3SATTRTIME_TOSERVER: 1381 getnanotime(&(a)->va_atime); 1382 break; 1383 } 1384 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 1385 if (tl == NULL) 1386 return EBADRPC; 1387 switch (fxdr_unsigned(int, *tl)) { 1388 case NFSV3SATTRTIME_TOCLIENT: 1389 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); 1390 if (tl == NULL) 1391 return EBADRPC; 1392 fxdr_nfsv3time(tl, &(a)->va_mtime); 1393 break; 1394 case NFSV3SATTRTIME_TOSERVER: 1395 getnanotime(&(a)->va_mtime); 1396 break; 1397 } 1398 return 0; 1399} 1400