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