nfs_srvsubs.c revision 164585
1/*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 164585 2006-11-24 11:53:16Z rwatson $"); 37 38/* 39 * These functions support the macros and help fiddle mbuf chains for 40 * the nfs op functions. They do things like create the rpc header and 41 * copy data between mbuf chains and uio lists. 42 */ 43 44#include "opt_inet6.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/bio.h> 50#include <sys/buf.h> 51#include <sys/proc.h> 52#include <sys/mount.h> 53#include <sys/vnode.h> 54#include <sys/namei.h> 55#include <sys/mbuf.h> 56#include <sys/refcount.h> 57#include <sys/socket.h> 58#include <sys/stat.h> 59#include <sys/malloc.h> 60#include <sys/module.h> 61#include <sys/sysent.h> 62#include <sys/syscall.h> 63#include <sys/sysproto.h> 64 65#include <vm/vm.h> 66#include <vm/vm_object.h> 67#include <vm/vm_extern.h> 68#include <vm/uma.h> 69 70#include <nfs/rpcv2.h> 71#include <nfs/nfsproto.h> 72#include <nfsserver/nfs.h> 73#include <nfs/xdr_subs.h> 74#include <nfsserver/nfsm_subs.h> 75 76#include <netinet/in.h> 77 78/* 79 * Data items converted to xdr at startup, since they are constant 80 * This is kinda hokey, but may save a little time doing byte swaps 81 */ 82u_int32_t nfsrv_nfs_xdrneg1; 83u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply, 84 nfsrv_rpc_msgdenied, nfsrv_rpc_autherr, 85 nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted; 86u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false; 87 88/* And other global data */ 89static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, 90 NFLNK, NFNON, NFCHR, NFNON }; 91#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 92#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 93 94int nfsrv_ticks; 95 96struct nfssvc_sockhead nfssvc_sockhead; 97int nfssvc_sockhead_flag; 98struct nfsd_head nfsd_head; 99int nfsd_head_flag; 100 101static int nfs_prev_nfssvc_sy_narg; 102static sy_call_t *nfs_prev_nfssvc_sy_call; 103 104struct mtx nfsd_mtx; 105 106/* 107 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 108 */ 109const int nfsrv_nfsv3_procid[NFS_NPROCS] = { 110 NFSPROC_NULL, 111 NFSPROC_GETATTR, 112 NFSPROC_SETATTR, 113 NFSPROC_NOOP, 114 NFSPROC_LOOKUP, 115 NFSPROC_READLINK, 116 NFSPROC_READ, 117 NFSPROC_NOOP, 118 NFSPROC_WRITE, 119 NFSPROC_CREATE, 120 NFSPROC_REMOVE, 121 NFSPROC_RENAME, 122 NFSPROC_LINK, 123 NFSPROC_SYMLINK, 124 NFSPROC_MKDIR, 125 NFSPROC_RMDIR, 126 NFSPROC_READDIR, 127 NFSPROC_FSSTAT, 128 NFSPROC_NOOP, 129 NFSPROC_NOOP, 130 NFSPROC_NOOP, 131 NFSPROC_NOOP, 132 NFSPROC_NOOP, 133}; 134 135/* 136 * and the reverse mapping from generic to Version 2 procedure numbers 137 */ 138const int nfsrvv2_procid[NFS_NPROCS] = { 139 NFSV2PROC_NULL, 140 NFSV2PROC_GETATTR, 141 NFSV2PROC_SETATTR, 142 NFSV2PROC_LOOKUP, 143 NFSV2PROC_NOOP, 144 NFSV2PROC_READLINK, 145 NFSV2PROC_READ, 146 NFSV2PROC_WRITE, 147 NFSV2PROC_CREATE, 148 NFSV2PROC_MKDIR, 149 NFSV2PROC_SYMLINK, 150 NFSV2PROC_CREATE, 151 NFSV2PROC_REMOVE, 152 NFSV2PROC_RMDIR, 153 NFSV2PROC_RENAME, 154 NFSV2PROC_LINK, 155 NFSV2PROC_READDIR, 156 NFSV2PROC_NOOP, 157 NFSV2PROC_STATFS, 158 NFSV2PROC_NOOP, 159 NFSV2PROC_NOOP, 160 NFSV2PROC_NOOP, 161 NFSV2PROC_NOOP, 162}; 163 164/* 165 * Maps errno values to nfs error numbers. 166 * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not 167 * specifically defined in RFC 1094. 168 */ 169static const u_char nfsrv_v2errmap[ELAST] = { 170 NFSERR_PERM, NFSERR_NOENT, 0, 0, 0, 171 NFSERR_NXIO, 0, 0, 0, 0, 172 0, 0, NFSERR_ACCES, 0, 0, 173 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR, 174 NFSERR_ISDIR, 0, 0, 0, 0, 175 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS, 176 0, 0, 0, 0, 0, 177 0, 0, 0, 0, 0, 178 0, 0, 0, 0, 0, 179 0, 0, 0, 0, 0, 180 0, 0, 0, 0, 0, 181 0, 0, 0, 0, 0, 182 0, 0, NFSERR_NAMETOL, 0, 0, 183 NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE, 184 0 185}; 186 187/* 188 * Maps errno values to nfs error numbers. 189 * Although it is not obvious whether or not NFS clients really care if 190 * a returned error value is in the specified list for the procedure, the 191 * safest thing to do is filter them appropriately. For Version 2, the 192 * X/Open XNFS document is the only specification that defines error values 193 * for each RPC (The RFC simply lists all possible error values for all RPCs), 194 * so I have decided to not do this for Version 2. 195 * The first entry is the default error return and the rest are the valid 196 * errors for that RPC in increasing numeric order. 197 */ 198static const short nfsv3err_null[] = { 199 0, 200 0, 201}; 202 203static const short nfsv3err_getattr[] = { 204 NFSERR_IO, 205 NFSERR_IO, 206 NFSERR_STALE, 207 NFSERR_BADHANDLE, 208 NFSERR_SERVERFAULT, 209 0, 210}; 211 212static const short nfsv3err_setattr[] = { 213 NFSERR_IO, 214 NFSERR_PERM, 215 NFSERR_IO, 216 NFSERR_ACCES, 217 NFSERR_INVAL, 218 NFSERR_NOSPC, 219 NFSERR_ROFS, 220 NFSERR_DQUOT, 221 NFSERR_STALE, 222 NFSERR_BADHANDLE, 223 NFSERR_NOT_SYNC, 224 NFSERR_SERVERFAULT, 225 0, 226}; 227 228static const short nfsv3err_lookup[] = { 229 NFSERR_IO, 230 NFSERR_NOENT, 231 NFSERR_IO, 232 NFSERR_ACCES, 233 NFSERR_NOTDIR, 234 NFSERR_NAMETOL, 235 NFSERR_STALE, 236 NFSERR_BADHANDLE, 237 NFSERR_SERVERFAULT, 238 0, 239}; 240 241static const short nfsv3err_access[] = { 242 NFSERR_IO, 243 NFSERR_IO, 244 NFSERR_STALE, 245 NFSERR_BADHANDLE, 246 NFSERR_SERVERFAULT, 247 0, 248}; 249 250static const short nfsv3err_readlink[] = { 251 NFSERR_IO, 252 NFSERR_IO, 253 NFSERR_ACCES, 254 NFSERR_INVAL, 255 NFSERR_STALE, 256 NFSERR_BADHANDLE, 257 NFSERR_NOTSUPP, 258 NFSERR_SERVERFAULT, 259 0, 260}; 261 262static const short nfsv3err_read[] = { 263 NFSERR_IO, 264 NFSERR_IO, 265 NFSERR_NXIO, 266 NFSERR_ACCES, 267 NFSERR_INVAL, 268 NFSERR_STALE, 269 NFSERR_BADHANDLE, 270 NFSERR_SERVERFAULT, 271 0, 272}; 273 274static const short nfsv3err_write[] = { 275 NFSERR_IO, 276 NFSERR_IO, 277 NFSERR_ACCES, 278 NFSERR_INVAL, 279 NFSERR_FBIG, 280 NFSERR_NOSPC, 281 NFSERR_ROFS, 282 NFSERR_DQUOT, 283 NFSERR_STALE, 284 NFSERR_BADHANDLE, 285 NFSERR_SERVERFAULT, 286 0, 287}; 288 289static const short nfsv3err_create[] = { 290 NFSERR_IO, 291 NFSERR_IO, 292 NFSERR_ACCES, 293 NFSERR_EXIST, 294 NFSERR_NOTDIR, 295 NFSERR_NOSPC, 296 NFSERR_ROFS, 297 NFSERR_NAMETOL, 298 NFSERR_DQUOT, 299 NFSERR_STALE, 300 NFSERR_BADHANDLE, 301 NFSERR_NOTSUPP, 302 NFSERR_SERVERFAULT, 303 0, 304}; 305 306static const short nfsv3err_mkdir[] = { 307 NFSERR_IO, 308 NFSERR_IO, 309 NFSERR_ACCES, 310 NFSERR_EXIST, 311 NFSERR_NOTDIR, 312 NFSERR_NOSPC, 313 NFSERR_ROFS, 314 NFSERR_NAMETOL, 315 NFSERR_DQUOT, 316 NFSERR_STALE, 317 NFSERR_BADHANDLE, 318 NFSERR_NOTSUPP, 319 NFSERR_SERVERFAULT, 320 0, 321}; 322 323static const short nfsv3err_symlink[] = { 324 NFSERR_IO, 325 NFSERR_IO, 326 NFSERR_ACCES, 327 NFSERR_EXIST, 328 NFSERR_NOTDIR, 329 NFSERR_NOSPC, 330 NFSERR_ROFS, 331 NFSERR_NAMETOL, 332 NFSERR_DQUOT, 333 NFSERR_STALE, 334 NFSERR_BADHANDLE, 335 NFSERR_NOTSUPP, 336 NFSERR_SERVERFAULT, 337 0, 338}; 339 340static const short nfsv3err_mknod[] = { 341 NFSERR_IO, 342 NFSERR_IO, 343 NFSERR_ACCES, 344 NFSERR_EXIST, 345 NFSERR_NOTDIR, 346 NFSERR_NOSPC, 347 NFSERR_ROFS, 348 NFSERR_NAMETOL, 349 NFSERR_DQUOT, 350 NFSERR_STALE, 351 NFSERR_BADHANDLE, 352 NFSERR_NOTSUPP, 353 NFSERR_SERVERFAULT, 354 NFSERR_BADTYPE, 355 0, 356}; 357 358static const short nfsv3err_remove[] = { 359 NFSERR_IO, 360 NFSERR_NOENT, 361 NFSERR_IO, 362 NFSERR_ACCES, 363 NFSERR_NOTDIR, 364 NFSERR_ROFS, 365 NFSERR_NAMETOL, 366 NFSERR_STALE, 367 NFSERR_BADHANDLE, 368 NFSERR_SERVERFAULT, 369 0, 370}; 371 372static const short nfsv3err_rmdir[] = { 373 NFSERR_IO, 374 NFSERR_NOENT, 375 NFSERR_IO, 376 NFSERR_ACCES, 377 NFSERR_EXIST, 378 NFSERR_NOTDIR, 379 NFSERR_INVAL, 380 NFSERR_ROFS, 381 NFSERR_NAMETOL, 382 NFSERR_NOTEMPTY, 383 NFSERR_STALE, 384 NFSERR_BADHANDLE, 385 NFSERR_NOTSUPP, 386 NFSERR_SERVERFAULT, 387 0, 388}; 389 390static const short nfsv3err_rename[] = { 391 NFSERR_IO, 392 NFSERR_NOENT, 393 NFSERR_IO, 394 NFSERR_ACCES, 395 NFSERR_EXIST, 396 NFSERR_XDEV, 397 NFSERR_NOTDIR, 398 NFSERR_ISDIR, 399 NFSERR_INVAL, 400 NFSERR_NOSPC, 401 NFSERR_ROFS, 402 NFSERR_MLINK, 403 NFSERR_NAMETOL, 404 NFSERR_NOTEMPTY, 405 NFSERR_DQUOT, 406 NFSERR_STALE, 407 NFSERR_BADHANDLE, 408 NFSERR_NOTSUPP, 409 NFSERR_SERVERFAULT, 410 0, 411}; 412 413static const short nfsv3err_link[] = { 414 NFSERR_IO, 415 NFSERR_IO, 416 NFSERR_ACCES, 417 NFSERR_EXIST, 418 NFSERR_XDEV, 419 NFSERR_NOTDIR, 420 NFSERR_INVAL, 421 NFSERR_NOSPC, 422 NFSERR_ROFS, 423 NFSERR_MLINK, 424 NFSERR_NAMETOL, 425 NFSERR_DQUOT, 426 NFSERR_STALE, 427 NFSERR_BADHANDLE, 428 NFSERR_NOTSUPP, 429 NFSERR_SERVERFAULT, 430 0, 431}; 432 433static const short nfsv3err_readdir[] = { 434 NFSERR_IO, 435 NFSERR_IO, 436 NFSERR_ACCES, 437 NFSERR_NOTDIR, 438 NFSERR_STALE, 439 NFSERR_BADHANDLE, 440 NFSERR_BAD_COOKIE, 441 NFSERR_TOOSMALL, 442 NFSERR_SERVERFAULT, 443 0, 444}; 445 446static const short nfsv3err_readdirplus[] = { 447 NFSERR_IO, 448 NFSERR_IO, 449 NFSERR_ACCES, 450 NFSERR_NOTDIR, 451 NFSERR_STALE, 452 NFSERR_BADHANDLE, 453 NFSERR_BAD_COOKIE, 454 NFSERR_NOTSUPP, 455 NFSERR_TOOSMALL, 456 NFSERR_SERVERFAULT, 457 0, 458}; 459 460static const short nfsv3err_fsstat[] = { 461 NFSERR_IO, 462 NFSERR_IO, 463 NFSERR_STALE, 464 NFSERR_BADHANDLE, 465 NFSERR_SERVERFAULT, 466 0, 467}; 468 469static const short nfsv3err_fsinfo[] = { 470 NFSERR_STALE, 471 NFSERR_STALE, 472 NFSERR_BADHANDLE, 473 NFSERR_SERVERFAULT, 474 0, 475}; 476 477static const short nfsv3err_pathconf[] = { 478 NFSERR_STALE, 479 NFSERR_STALE, 480 NFSERR_BADHANDLE, 481 NFSERR_SERVERFAULT, 482 0, 483}; 484 485static const short nfsv3err_commit[] = { 486 NFSERR_IO, 487 NFSERR_IO, 488 NFSERR_STALE, 489 NFSERR_BADHANDLE, 490 NFSERR_SERVERFAULT, 491 0, 492}; 493 494static const short *nfsrv_v3errmap[] = { 495 nfsv3err_null, 496 nfsv3err_getattr, 497 nfsv3err_setattr, 498 nfsv3err_lookup, 499 nfsv3err_access, 500 nfsv3err_readlink, 501 nfsv3err_read, 502 nfsv3err_write, 503 nfsv3err_create, 504 nfsv3err_mkdir, 505 nfsv3err_symlink, 506 nfsv3err_mknod, 507 nfsv3err_remove, 508 nfsv3err_rmdir, 509 nfsv3err_rename, 510 nfsv3err_link, 511 nfsv3err_readdir, 512 nfsv3err_readdirplus, 513 nfsv3err_fsstat, 514 nfsv3err_fsinfo, 515 nfsv3err_pathconf, 516 nfsv3err_commit, 517}; 518 519/* 520 * Called once to initialize data structures... 521 */ 522static int 523nfsrv_modevent(module_t mod, int type, void *data) 524{ 525 int error = 0; 526 527 NET_LOCK_GIANT(); 528 switch (type) { 529 case MOD_LOAD: 530 mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); 531 nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 532 nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 533 nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 534 nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 535 nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 536 nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 537 nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 538 nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 539 nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 540 nfsrv_nfs_true = txdr_unsigned(TRUE); 541 nfsrv_nfs_false = txdr_unsigned(FALSE); 542 nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 543 nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 544 if (nfsrv_ticks < 1) 545 nfsrv_ticks = 1; 546 547 nfsrv_initcache(); /* Init the server request cache */ 548 NFSD_LOCK(); 549 nfsrv_init(0); /* Init server data structures */ 550 if (debug_mpsafenet) 551 callout_init(&nfsrv_callout, CALLOUT_MPSAFE); 552 else 553 callout_init(&nfsrv_callout, 0); 554 NFSD_UNLOCK(); 555 nfsrv_timer(0); 556 557 /* XXX: Should use SYSCALL_MODULE() */ 558 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 559 sysent[SYS_nfssvc].sy_narg = 2; 560 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 561 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 562 break; 563 564 case MOD_UNLOAD: 565 if (nfsrv_numnfsd != 0) { 566 error = EBUSY; 567 break; 568 } 569 570 callout_drain(&nfsrv_callout); 571 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 572 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 573 nfsrv_destroycache(); /* Free the server request cache */ 574 mtx_destroy(&nfsd_mtx); 575 break; 576 default: 577 error = EOPNOTSUPP; 578 break; 579 } 580 NET_UNLOCK_GIANT(); 581 return error; 582} 583static moduledata_t nfsserver_mod = { 584 "nfsserver", 585 nfsrv_modevent, 586 NULL, 587}; 588DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 589 590/* So that loader and kldload(2) can find us, wherever we are.. */ 591MODULE_VERSION(nfsserver, 1); 592 593/* 594 * Set up nameidata for a lookup() call and do it. 595 * 596 * If pubflag is set, this call is done for a lookup operation on the 597 * public filehandle. In that case we allow crossing mountpoints and 598 * absolute pathnames. However, the caller is expected to check that 599 * the lookup result is within the public fs, and deny access if 600 * it is not. 601 * 602 * nfs_namei() clears out garbage fields that namei() might leave garbage. 603 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 604 * error occurs but the parent was not requested. 605 * 606 * dirp may be set whether an error is returned or not, and must be 607 * released by the caller. 608 */ 609int 610nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 611 struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 612 caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp, 613 int *retdirattr_retp, struct thread *td, int pubflag) 614{ 615 int i, rem; 616 struct mbuf *md; 617 char *fromcp, *tocp, *cp; 618 struct iovec aiov; 619 struct uio auio; 620 struct vnode *dp; 621 int error, rdonly, linklen; 622 struct componentname *cnp = &ndp->ni_cnd; 623 int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; 624 625 NFSD_LOCK_ASSERT(); 626 NFSD_UNLOCK(); 627 628 *retdirp = NULL; 629 cnp->cn_flags |= NOMACCHECK; 630 cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 631 632 /* 633 * Copy the name from the mbuf list to ndp->ni_pnbuf 634 * and set the various ndp fields appropriately. 635 */ 636 fromcp = *dposp; 637 tocp = cnp->cn_pnbuf; 638 md = *mdp; 639 rem = mtod(md, caddr_t) + md->m_len - fromcp; 640 for (i = 0; i < len; i++) { 641 while (rem == 0) { 642 md = md->m_next; 643 if (md == NULL) { 644 error = EBADRPC; 645 goto out_nogiant; 646 } 647 fromcp = mtod(md, caddr_t); 648 rem = md->m_len; 649 } 650 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 651 error = EACCES; 652 goto out_nogiant; 653 } 654 *tocp++ = *fromcp++; 655 rem--; 656 } 657 *tocp = '\0'; 658 *mdp = md; 659 *dposp = fromcp; 660 len = nfsm_rndup(len)-len; 661 if (len > 0) { 662 if (rem >= len) 663 *dposp += len; 664 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 665 goto out_nogiant; 666 } 667 668 /* 669 * Extract and set starting directory. 670 * 671 * XXXRW: For now, acquire Giant unconditionally to avoid tracking it 672 * on multiple vnodes. 673 */ 674 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 675 nam, &rdonly, pubflag); 676 mtx_lock(&Giant); /* VFS */ 677 if (error) 678 goto out; 679 if (dp->v_type != VDIR) { 680 vrele(dp); 681 error = ENOTDIR; 682 goto out; 683 } 684 685 if (rdonly) 686 cnp->cn_flags |= RDONLY; 687 688 /* 689 * Set return directory. Reference to dp is implicitly transfered 690 * to the returned pointer 691 */ 692 *retdirp = dp; 693 if (v3) { 694 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 695 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp, 696 ndp->ni_cnd.cn_cred, td); 697 VOP_UNLOCK(dp, 0, td); 698 } 699 700 if (pubflag) { 701 /* 702 * Oh joy. For WebNFS, handle those pesky '%' escapes, 703 * and the 'native path' indicator. 704 */ 705 cp = uma_zalloc(namei_zone, M_WAITOK); 706 fromcp = cnp->cn_pnbuf; 707 tocp = cp; 708 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 709 switch ((unsigned char)*fromcp) { 710 case WEBNFS_NATIVE_CHAR: 711 /* 712 * 'Native' path for us is the same 713 * as a path according to the NFS spec, 714 * just skip the escape char. 715 */ 716 fromcp++; 717 break; 718 /* 719 * More may be added in the future, range 0x80-0xff 720 */ 721 default: 722 error = EIO; 723 uma_zfree(namei_zone, cp); 724 goto out; 725 } 726 } 727 /* 728 * Translate the '%' escapes, URL-style. 729 */ 730 while (*fromcp != '\0') { 731 if (*fromcp == WEBNFS_ESC_CHAR) { 732 if (fromcp[1] != '\0' && fromcp[2] != '\0') { 733 fromcp++; 734 *tocp++ = HEXSTRTOI(fromcp); 735 fromcp += 2; 736 continue; 737 } else { 738 error = ENOENT; 739 uma_zfree(namei_zone, cp); 740 goto out; 741 } 742 } else 743 *tocp++ = *fromcp++; 744 } 745 *tocp = '\0'; 746 uma_zfree(namei_zone, cnp->cn_pnbuf); 747 cnp->cn_pnbuf = cp; 748 } 749 750 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 751 ndp->ni_segflg = UIO_SYSSPACE; 752 753 if (pubflag) { 754 ndp->ni_rootdir = rootvnode; 755 ndp->ni_loopcnt = 0; 756 if (cnp->cn_pnbuf[0] == '/') 757 dp = rootvnode; 758 } else { 759 cnp->cn_flags |= NOCROSSMOUNT; 760 } 761 762 /* 763 * Initialize for scan, set ni_startdir and bump ref on dp again 764 * because lookup() will dereference ni_startdir. 765 */ 766 767 cnp->cn_thread = td; 768 VREF(dp); 769 ndp->ni_startdir = dp; 770 771 if (!lockleaf) 772 cnp->cn_flags |= LOCKLEAF; 773 for (;;) { 774 cnp->cn_nameptr = cnp->cn_pnbuf; 775 /* 776 * Call lookup() to do the real work. If an error occurs, 777 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 778 * we do not have to dereference anything before returning. 779 * In either case ni_startdir will be dereferenced and NULLed 780 * out. 781 */ 782 error = lookup(ndp); 783 if (error) 784 break; 785 786 /* 787 * Check for encountering a symbolic link. Trivial 788 * termination occurs if no symlink encountered. 789 * Note: zfree is safe because error is 0, so we will 790 * not zfree it again when we break. 791 */ 792 if ((cnp->cn_flags & ISSYMLINK) == 0) { 793 if (cnp->cn_flags & (SAVENAME | SAVESTART)) 794 cnp->cn_flags |= HASBUF; 795 else 796 uma_zfree(namei_zone, cnp->cn_pnbuf); 797 if (ndp->ni_vp && !lockleaf) 798 VOP_UNLOCK(ndp->ni_vp, 0, td); 799 break; 800 } 801 802 /* 803 * Validate symlink 804 */ 805 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 806 VOP_UNLOCK(ndp->ni_dvp, 0, td); 807 if (!pubflag) { 808 error = EINVAL; 809 goto badlink2; 810 } 811 812 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 813 error = ELOOP; 814 goto badlink2; 815 } 816 if (ndp->ni_pathlen > 1) 817 cp = uma_zalloc(namei_zone, M_WAITOK); 818 else 819 cp = cnp->cn_pnbuf; 820 aiov.iov_base = cp; 821 aiov.iov_len = MAXPATHLEN; 822 auio.uio_iov = &aiov; 823 auio.uio_iovcnt = 1; 824 auio.uio_offset = 0; 825 auio.uio_rw = UIO_READ; 826 auio.uio_segflg = UIO_SYSSPACE; 827 auio.uio_td = NULL; 828 auio.uio_resid = MAXPATHLEN; 829 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 830 if (error) { 831 badlink1: 832 if (ndp->ni_pathlen > 1) 833 uma_zfree(namei_zone, cp); 834 badlink2: 835 vput(ndp->ni_vp); 836 vrele(ndp->ni_dvp); 837 break; 838 } 839 linklen = MAXPATHLEN - auio.uio_resid; 840 if (linklen == 0) { 841 error = ENOENT; 842 goto badlink1; 843 } 844 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 845 error = ENAMETOOLONG; 846 goto badlink1; 847 } 848 849 /* 850 * Adjust or replace path 851 */ 852 if (ndp->ni_pathlen > 1) { 853 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 854 uma_zfree(namei_zone, cnp->cn_pnbuf); 855 cnp->cn_pnbuf = cp; 856 } else 857 cnp->cn_pnbuf[linklen] = '\0'; 858 ndp->ni_pathlen += linklen; 859 860 /* 861 * Cleanup refs for next loop and check if root directory 862 * should replace current directory. Normally ni_dvp 863 * becomes the new base directory and is cleaned up when 864 * we loop. Explicitly null pointers after invalidation 865 * to clarify operation. 866 */ 867 vput(ndp->ni_vp); 868 ndp->ni_vp = NULL; 869 870 if (cnp->cn_pnbuf[0] == '/') { 871 vrele(ndp->ni_dvp); 872 ndp->ni_dvp = ndp->ni_rootdir; 873 VREF(ndp->ni_dvp); 874 } 875 ndp->ni_startdir = ndp->ni_dvp; 876 ndp->ni_dvp = NULL; 877 } 878 if (!lockleaf) 879 cnp->cn_flags &= ~LOCKLEAF; 880 if (cnp->cn_flags & GIANTHELD) { 881 mtx_unlock(&Giant); 882 cnp->cn_flags &= ~GIANTHELD; 883 } 884 885 /* 886 * nfs_namei() guarentees that fields will not contain garbage 887 * whether an error occurs or not. This allows the caller to track 888 * cleanup state trivially. 889 */ 890out: 891 mtx_unlock(&Giant); /* VFS */ 892out_nogiant: 893 if (error) { 894 uma_zfree(namei_zone, cnp->cn_pnbuf); 895 ndp->ni_vp = NULL; 896 ndp->ni_dvp = NULL; 897 ndp->ni_startdir = NULL; 898 cnp->cn_flags &= ~HASBUF; 899 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 900 ndp->ni_dvp = NULL; 901 } 902 NFSD_LOCK(); 903 return (error); 904} 905 906/* 907 * A fiddled version of m_adj() that ensures null fill to a long 908 * boundary and only trims off the back end 909 */ 910void 911nfsm_adj(struct mbuf *mp, int len, int nul) 912{ 913 struct mbuf *m; 914 int count, i; 915 char *cp; 916 917 NFSD_LOCK_DONTCARE(); 918 919 /* 920 * Trim from tail. Scan the mbuf chain, 921 * calculating its length and finding the last mbuf. 922 * If the adjustment only affects this mbuf, then just 923 * adjust and return. Otherwise, rescan and truncate 924 * after the remaining size. 925 */ 926 count = 0; 927 m = mp; 928 for (;;) { 929 count += m->m_len; 930 if (m->m_next == NULL) 931 break; 932 m = m->m_next; 933 } 934 if (m->m_len > len) { 935 m->m_len -= len; 936 if (nul > 0) { 937 cp = mtod(m, caddr_t)+m->m_len-nul; 938 for (i = 0; i < nul; i++) 939 *cp++ = '\0'; 940 } 941 return; 942 } 943 count -= len; 944 if (count < 0) 945 count = 0; 946 /* 947 * Correct length for chain is "count". 948 * Find the mbuf with last data, adjust its length, 949 * and toss data from remaining mbufs on chain. 950 */ 951 for (m = mp; m; m = m->m_next) { 952 if (m->m_len >= count) { 953 m->m_len = count; 954 if (nul > 0) { 955 cp = mtod(m, caddr_t)+m->m_len-nul; 956 for (i = 0; i < nul; i++) 957 *cp++ = '\0'; 958 } 959 if (m->m_next != NULL) { 960 m_freem(m->m_next); 961 m->m_next = NULL; 962 } 963 break; 964 } 965 count -= m->m_len; 966 } 967} 968 969/* 970 * Make these functions instead of macros, so that the kernel text size 971 * doesn't get too big... 972 */ 973void 974nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 975 struct vattr *before_vap, int after_ret, struct vattr *after_vap, 976 struct mbuf **mbp, char **bposp) 977{ 978 struct mbuf *mb = *mbp; 979 char *bpos = *bposp; 980 u_int32_t *tl; 981 982 if (before_ret) { 983 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 984 *tl = nfsrv_nfs_false; 985 } else { 986 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 987 *tl++ = nfsrv_nfs_true; 988 txdr_hyper(before_vap->va_size, tl); 989 tl += 2; 990 txdr_nfsv3time(&(before_vap->va_mtime), tl); 991 tl += 2; 992 txdr_nfsv3time(&(before_vap->va_ctime), tl); 993 } 994 *bposp = bpos; 995 *mbp = mb; 996 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 997} 998 999void 1000nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 1001 struct vattr *after_vap, struct mbuf **mbp, char **bposp) 1002{ 1003 struct mbuf *mb = *mbp; 1004 char *bpos = *bposp; 1005 u_int32_t *tl; 1006 struct nfs_fattr *fp; 1007 1008 if (after_ret) { 1009 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 1010 *tl = nfsrv_nfs_false; 1011 } else { 1012 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1013 *tl++ = nfsrv_nfs_true; 1014 fp = (struct nfs_fattr *)tl; 1015 nfsm_srvfattr(nfsd, after_vap, fp); 1016 } 1017 *mbp = mb; 1018 *bposp = bpos; 1019} 1020 1021void 1022nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 1023 struct nfs_fattr *fp) 1024{ 1025 1026 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1027 fp->fa_uid = txdr_unsigned(vap->va_uid); 1028 fp->fa_gid = txdr_unsigned(vap->va_gid); 1029 if (nfsd->nd_flag & ND_NFSV3) { 1030 fp->fa_type = vtonfsv3_type(vap->va_type); 1031 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1032 txdr_hyper(vap->va_size, &fp->fa3_size); 1033 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1034 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 1035 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 1036 fp->fa3_fsid.nfsuquad[0] = 0; 1037 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1038 fp->fa3_fileid.nfsuquad[0] = 0; 1039 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1040 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1041 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1042 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1043 } else { 1044 fp->fa_type = vtonfsv2_type(vap->va_type); 1045 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1046 fp->fa2_size = txdr_unsigned(vap->va_size); 1047 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1048 if (vap->va_type == VFIFO) 1049 fp->fa2_rdev = 0xffffffff; 1050 else 1051 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1052 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1053 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1054 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1055 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1056 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1057 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1058 } 1059} 1060 1061/* 1062 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1063 * - look up fsid in mount list (if not found ret error) 1064 * - get vp and export rights by calling VFS_FHTOVP() 1065 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1066 * - if not lockflag unlock it with VOP_UNLOCK() 1067 * 1068 * As this routine may acquire Giant and may sleep, it can't be called with 1069 * nfsd_mtx. Caller should invoke nfsrv_fhtovp_locked() if the lock is held 1070 * so that it can be automatically dropped and re-acquired. 1071 */ 1072int 1073nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 1074 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 1075 int *rdonlyp, int pubflag) 1076{ 1077 struct thread *td = curthread; /* XXX */ 1078 struct mount *mp; 1079 int i; 1080 struct ucred *credanon; 1081 int error, exflags; 1082 int vfslocked; 1083#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1084 struct sockaddr_int *saddr; 1085#endif 1086 1087 NFSD_UNLOCK_ASSERT(); 1088 1089 *vpp = NULL; 1090 1091 if (nfs_ispublicfh(fhp)) { 1092 if (!pubflag || !nfs_pub.np_valid) 1093 return (ESTALE); 1094 fhp = &nfs_pub.np_handle; 1095 } 1096 1097 mp = vfs_getvfs(&fhp->fh_fsid); 1098 if (!mp) 1099 return (ESTALE); 1100 vfslocked = VFS_LOCK_GIANT(mp); 1101 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1102 if (error) 1103 goto out; 1104 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1105 if (error) 1106 goto out; 1107#ifdef MNT_EXNORESPORT 1108 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1109 saddr = (struct sockaddr_in *)nam; 1110 if ((saddr->sin_family == AF_INET || 1111 saddr->sin_family == AF_INET6) && 1112 /* same code for INET and INET6: sin*_port at same offet */ 1113 ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1114 vput(*vpp); 1115 *vpp = NULL; 1116 error = NFSERR_AUTHERR | AUTH_TOOWEAK; 1117 } 1118 } 1119#endif 1120 /* 1121 * Check/setup credentials. 1122 */ 1123 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1124 cred->cr_uid = credanon->cr_uid; 1125 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1126 cred->cr_groups[i] = credanon->cr_groups[i]; 1127 cred->cr_ngroups = i; 1128 } 1129 if (exflags & MNT_EXRDONLY) 1130 *rdonlyp = 1; 1131 else 1132 *rdonlyp = 0; 1133 1134 if (!lockflag) 1135 VOP_UNLOCK(*vpp, 0, td); 1136out: 1137 vfs_rel(mp); 1138 VFS_UNLOCK_GIANT(vfslocked); 1139 return (error); 1140} 1141 1142/* 1143 * Version of nfsrv_fhtovp() that can be called holding nfsd_mtx: it will 1144 * drop and re-acquire the lock for the caller. 1145 */ 1146int 1147nfsrv_fhtovp_locked(fhandle_t *fhp, int lockflag, struct vnode **vpp, 1148 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 1149 int *rdonlyp, int pubflag) 1150{ 1151 int error; 1152 1153 NFSD_LOCK_ASSERT(); 1154 NFSD_UNLOCK(); 1155 error = nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, 1156 pubflag); 1157 NFSD_LOCK(); 1158 return (error); 1159} 1160 1161/* 1162 * WebNFS: check if a filehandle is a public filehandle. For v3, this 1163 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 1164 * transformed this to all zeroes in both cases, so check for it. 1165 */ 1166int 1167nfs_ispublicfh(fhandle_t *fhp) 1168{ 1169 char *cp = (char *)fhp; 1170 int i; 1171 1172 NFSD_LOCK_DONTCARE(); 1173 1174 for (i = 0; i < NFSX_V3FH; i++) 1175 if (*cp++ != 0) 1176 return (FALSE); 1177 return (TRUE); 1178} 1179 1180/* 1181 * This function compares two net addresses by family and returns TRUE 1182 * if they are the same host. 1183 * If there is any doubt, return FALSE. 1184 * The AF_INET family is handled as a special case so that address mbufs 1185 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1186 */ 1187int 1188netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 1189{ 1190 struct sockaddr_in *inetaddr; 1191 1192 NFSD_LOCK_DONTCARE(); 1193 1194 switch (family) { 1195 case AF_INET: 1196 inetaddr = (struct sockaddr_in *)nam; 1197 if (inetaddr->sin_family == AF_INET && 1198 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1199 return (1); 1200 break; 1201#ifdef INET6 1202 case AF_INET6: 1203 { 1204 register struct sockaddr_in6 *inet6addr1, *inet6addr2; 1205 1206 inet6addr1 = (struct sockaddr_in6 *)nam; 1207 inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 1208 /* XXX - should test sin6_scope_id ? */ 1209 if (inet6addr1->sin6_family == AF_INET6 && 1210 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 1211 &inet6addr2->sin6_addr)) 1212 return (1); 1213 break; 1214 } 1215#endif 1216 default: 1217 break; 1218 }; 1219 return (0); 1220} 1221 1222/* 1223 * Map errnos to NFS error numbers. For Version 3 also filter out error 1224 * numbers not specified for the associated procedure. 1225 */ 1226int 1227nfsrv_errmap(struct nfsrv_descript *nd, int err) 1228{ 1229 const short *defaulterrp, *errp; 1230 int e; 1231 1232 NFSD_LOCK_DONTCARE(); 1233 1234 if (nd->nd_flag & ND_NFSV3) { 1235 if (nd->nd_procnum <= NFSPROC_COMMIT) { 1236 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1237 while (*++errp) { 1238 if (*errp == err) 1239 return (err); 1240 else if (*errp > err) 1241 break; 1242 } 1243 return ((int)*defaulterrp); 1244 } else 1245 return (err & 0xffff); 1246 } 1247 e = 0; 1248 if (err <= ELAST) 1249 e = nfsrv_v2errmap[err - 1]; 1250 if (e != 0) 1251 return (e); 1252 return (NFSERR_IO); 1253} 1254 1255/* 1256 * Sort the group list in increasing numerical order. 1257 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1258 * that used to be here.) 1259 */ 1260void 1261nfsrvw_sort(gid_t *list, int num) 1262{ 1263 int i, j; 1264 gid_t v; 1265 1266 NFSD_LOCK_DONTCARE(); 1267 1268 /* Insertion sort. */ 1269 for (i = 1; i < num; i++) { 1270 v = list[i]; 1271 /* find correct slot for value v, moving others up */ 1272 for (j = i; --j >= 0 && v < list[j];) 1273 list[j + 1] = list[j]; 1274 list[j + 1] = v; 1275 } 1276} 1277 1278/* 1279 * copy credentials making sure that the result can be compared with bcmp(). 1280 */ 1281void 1282nfsrv_setcred(struct ucred *incred, struct ucred *outcred) 1283{ 1284 int i; 1285 1286 NFSD_LOCK_DONTCARE(); 1287 1288 bzero((caddr_t)outcred, sizeof (struct ucred)); 1289 refcount_init(&outcred->cr_ref, 1); 1290 outcred->cr_uid = incred->cr_uid; 1291 outcred->cr_ngroups = incred->cr_ngroups; 1292 for (i = 0; i < incred->cr_ngroups; i++) 1293 outcred->cr_groups[i] = incred->cr_groups[i]; 1294 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 1295} 1296 1297/* 1298 * Helper functions for macros. 1299 */ 1300 1301void 1302nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 1303{ 1304 u_int32_t *tl; 1305 1306 NFSD_LOCK_DONTCARE(); 1307 1308 if (v3) { 1309 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1310 *tl++ = txdr_unsigned(NFSX_V3FH); 1311 bcopy(f, tl, NFSX_V3FH); 1312 } else { 1313 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 1314 bcopy(f, tl, NFSX_V2FH); 1315 } 1316} 1317 1318void 1319nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 1320{ 1321 u_int32_t *tl; 1322 1323 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1324 *tl++ = nfsrv_nfs_true; 1325 *tl++ = txdr_unsigned(NFSX_V3FH); 1326 bcopy(f, tl, NFSX_V3FH); 1327} 1328 1329int 1330nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1331{ 1332 u_int32_t *tl; 1333 1334 NFSD_LOCK_DONTCARE(); 1335 1336 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1337 if (tl == NULL) 1338 return EBADRPC; 1339 *s = fxdr_unsigned(int32_t, *tl); 1340 if (*s > m || *s <= 0) 1341 return EBADRPC; 1342 return 0; 1343} 1344 1345int 1346nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1347{ 1348 u_int32_t *tl; 1349 1350 NFSD_LOCK_DONTCARE(); 1351 1352 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1353 if (tl == NULL) 1354 return EBADRPC; 1355 *s = fxdr_unsigned(int32_t, *tl); 1356 if (*s > m) 1357 return NFSERR_NAMETOL; 1358 if (*s <= 0) 1359 return EBADRPC; 1360 return 0; 1361} 1362 1363void 1364nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 1365 char **bp, char **be, caddr_t bpos, int droplock) 1366{ 1367 struct mbuf *nmp; 1368 1369 NFSD_LOCK_DONTCARE(); 1370 1371 if (droplock) 1372 NFSD_LOCK_ASSERT(); 1373 else 1374 NFSD_UNLOCK_ASSERT(); 1375 1376 if (*bp >= *be) { 1377 if (*mp == mb) 1378 (*mp)->m_len += *bp - bpos; 1379 if (droplock) 1380 NFSD_UNLOCK(); 1381 MGET(nmp, M_TRYWAIT, MT_DATA); 1382 MCLGET(nmp, M_TRYWAIT); 1383 if (droplock) 1384 NFSD_LOCK(); 1385 nmp->m_len = NFSMSIZ(nmp); 1386 (*mp)->m_next = nmp; 1387 *mp = nmp; 1388 *bp = mtod(*mp, caddr_t); 1389 *be = *bp + (*mp)->m_len; 1390 } 1391 *tl = (u_int32_t *)*bp; 1392} 1393 1394int 1395nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 1396 caddr_t *dpos) 1397{ 1398 u_int32_t *tl; 1399 int fhlen; 1400 1401 NFSD_LOCK_DONTCARE(); 1402 1403 if (nfsd->nd_flag & ND_NFSV3) { 1404 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1405 if (tl == NULL) 1406 return EBADRPC; 1407 fhlen = fxdr_unsigned(int, *tl); 1408 if (fhlen != 0 && fhlen != NFSX_V3FH) 1409 return EBADRPC; 1410 } else { 1411 fhlen = NFSX_V2FH; 1412 } 1413 if (fhlen != 0) { 1414 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos); 1415 if (tl == NULL) 1416 return EBADRPC; 1417 bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 1418 } else { 1419 bzero((caddr_t)(f), NFSX_V3FH); 1420 } 1421 return 0; 1422} 1423 1424int 1425nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 1426{ 1427 u_int32_t *tl; 1428 int toclient = 0; 1429 1430 NFSD_LOCK_DONTCARE(); 1431 1432 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1433 if (tl == NULL) 1434 return EBADRPC; 1435 if (*tl == nfsrv_nfs_true) { 1436 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1437 if (tl == NULL) 1438 return EBADRPC; 1439 (a)->va_mode = nfstov_mode(*tl); 1440 } 1441 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1442 if (tl == NULL) 1443 return EBADRPC; 1444 if (*tl == nfsrv_nfs_true) { 1445 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1446 if (tl == NULL) 1447 return EBADRPC; 1448 (a)->va_uid = fxdr_unsigned(uid_t, *tl); 1449 } 1450 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1451 if (tl == NULL) 1452 return EBADRPC; 1453 if (*tl == nfsrv_nfs_true) { 1454 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1455 if (tl == NULL) 1456 return EBADRPC; 1457 (a)->va_gid = fxdr_unsigned(gid_t, *tl); 1458 } 1459 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1460 if (tl == NULL) 1461 return EBADRPC; 1462 if (*tl == nfsrv_nfs_true) { 1463 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 1464 if (tl == NULL) 1465 return EBADRPC; 1466 (a)->va_size = fxdr_hyper(tl); 1467 } 1468 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1469 if (tl == NULL) 1470 return EBADRPC; 1471 switch (fxdr_unsigned(int, *tl)) { 1472 case NFSV3SATTRTIME_TOCLIENT: 1473 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 1474 if (tl == NULL) 1475 return EBADRPC; 1476 fxdr_nfsv3time(tl, &(a)->va_atime); 1477 toclient = 1; 1478 break; 1479 case NFSV3SATTRTIME_TOSERVER: 1480 getnanotime(&(a)->va_atime); 1481 a->va_vaflags |= VA_UTIMES_NULL; 1482 break; 1483 } 1484 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1485 if (tl == NULL) 1486 return EBADRPC; 1487 switch (fxdr_unsigned(int, *tl)) { 1488 case NFSV3SATTRTIME_TOCLIENT: 1489 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 1490 if (tl == NULL) 1491 return EBADRPC; 1492 fxdr_nfsv3time(tl, &(a)->va_mtime); 1493 a->va_vaflags &= ~VA_UTIMES_NULL; 1494 break; 1495 case NFSV3SATTRTIME_TOSERVER: 1496 getnanotime(&(a)->va_mtime); 1497 if (toclient == 0) 1498 a->va_vaflags |= VA_UTIMES_NULL; 1499 break; 1500 } 1501 return 0; 1502} 1503