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