nfs_srvsubs.c revision 171744
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 171744 2007-08-06 14:26:03Z 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 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 nfsrv_destroycache(); /* Free the server request cache */ 573 mtx_destroy(&nfsd_mtx); 574 break; 575 default: 576 error = EOPNOTSUPP; 577 break; 578 } 579 return error; 580} 581static moduledata_t nfsserver_mod = { 582 "nfsserver", 583 nfsrv_modevent, 584 NULL, 585}; 586DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 587 588/* So that loader and kldload(2) can find us, wherever we are.. */ 589MODULE_VERSION(nfsserver, 1); 590 591/* 592 * Set up nameidata for a lookup() call and do it. 593 * 594 * If pubflag is set, this call is done for a lookup operation on the 595 * public filehandle. In that case we allow crossing mountpoints and 596 * absolute pathnames. However, the caller is expected to check that 597 * the lookup result is within the public fs, and deny access if 598 * it is not. 599 * 600 * nfs_namei() clears out garbage fields that namei() might leave garbage. 601 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 602 * error occurs but the parent was not requested. 603 * 604 * dirp may be set whether an error is returned or not, and must be 605 * released by the caller. 606 */ 607int 608nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 609 struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 610 caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp, 611 int *retdirattr_retp, struct thread *td, int pubflag) 612{ 613 int i, rem; 614 struct mbuf *md; 615 char *fromcp, *tocp, *cp; 616 struct iovec aiov; 617 struct uio auio; 618 struct vnode *dp; 619 int error, rdonly, linklen; 620 struct componentname *cnp = &ndp->ni_cnd; 621 int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; 622 int dvfslocked; 623 int vfslocked; 624 625 vfslocked = 0; 626 dvfslocked = 0; 627 *retdirp = NULL; 628 cnp->cn_flags |= NOMACCHECK; 629 cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 630 631 /* 632 * Copy the name from the mbuf list to ndp->ni_pnbuf 633 * and set the various ndp fields appropriately. 634 */ 635 fromcp = *dposp; 636 tocp = cnp->cn_pnbuf; 637 md = *mdp; 638 rem = mtod(md, caddr_t) + md->m_len - fromcp; 639 for (i = 0; i < len; i++) { 640 while (rem == 0) { 641 md = md->m_next; 642 if (md == NULL) { 643 error = EBADRPC; 644 goto out; 645 } 646 fromcp = mtod(md, caddr_t); 647 rem = md->m_len; 648 } 649 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 650 error = EACCES; 651 goto out; 652 } 653 *tocp++ = *fromcp++; 654 rem--; 655 } 656 *tocp = '\0'; 657 *mdp = md; 658 *dposp = fromcp; 659 len = nfsm_rndup(len)-len; 660 if (len > 0) { 661 if (rem >= len) 662 *dposp += len; 663 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 664 goto out; 665 } 666 667 /* 668 * Extract and set starting directory. 669 */ 670 error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked, 671 ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag); 672 if (error) 673 goto out; 674 vfslocked = VFS_LOCK_GIANT(dp->v_mount); 675 if (dp->v_type != VDIR) { 676 vrele(dp); 677 error = ENOTDIR; 678 goto out; 679 } 680 681 if (rdonly) 682 cnp->cn_flags |= RDONLY; 683 684 /* 685 * Set return directory. Reference to dp is implicitly transfered 686 * to the returned pointer 687 */ 688 *retdirp = dp; 689 if (v3) { 690 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 691 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp, 692 ndp->ni_cnd.cn_cred, td); 693 VOP_UNLOCK(dp, 0, td); 694 } 695 696 if (pubflag) { 697 /* 698 * Oh joy. For WebNFS, handle those pesky '%' escapes, 699 * and the 'native path' indicator. 700 */ 701 cp = uma_zalloc(namei_zone, M_WAITOK); 702 fromcp = cnp->cn_pnbuf; 703 tocp = cp; 704 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 705 switch ((unsigned char)*fromcp) { 706 case WEBNFS_NATIVE_CHAR: 707 /* 708 * 'Native' path for us is the same 709 * as a path according to the NFS spec, 710 * just skip the escape char. 711 */ 712 fromcp++; 713 break; 714 /* 715 * More may be added in the future, range 0x80-0xff 716 */ 717 default: 718 error = EIO; 719 uma_zfree(namei_zone, cp); 720 goto out; 721 } 722 } 723 /* 724 * Translate the '%' escapes, URL-style. 725 */ 726 while (*fromcp != '\0') { 727 if (*fromcp == WEBNFS_ESC_CHAR) { 728 if (fromcp[1] != '\0' && fromcp[2] != '\0') { 729 fromcp++; 730 *tocp++ = HEXSTRTOI(fromcp); 731 fromcp += 2; 732 continue; 733 } else { 734 error = ENOENT; 735 uma_zfree(namei_zone, cp); 736 goto out; 737 } 738 } else 739 *tocp++ = *fromcp++; 740 } 741 *tocp = '\0'; 742 uma_zfree(namei_zone, cnp->cn_pnbuf); 743 cnp->cn_pnbuf = cp; 744 } 745 746 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 747 ndp->ni_segflg = UIO_SYSSPACE; 748 749 if (pubflag) { 750 ndp->ni_rootdir = rootvnode; 751 ndp->ni_loopcnt = 0; 752 if (cnp->cn_pnbuf[0] == '/') { 753 int tvfslocked; 754 755 tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount); 756 VFS_UNLOCK_GIANT(vfslocked); 757 dp = rootvnode; 758 vfslocked = tvfslocked; 759 } 760 } else { 761 cnp->cn_flags |= NOCROSSMOUNT; 762 } 763 764 /* 765 * Initialize for scan, set ni_startdir and bump ref on dp again 766 * because lookup() will dereference ni_startdir. 767 */ 768 769 cnp->cn_thread = td; 770 VREF(dp); 771 ndp->ni_startdir = dp; 772 773 if (!lockleaf) 774 cnp->cn_flags |= LOCKLEAF; 775 for (;;) { 776 cnp->cn_nameptr = cnp->cn_pnbuf; 777 /* 778 * Call lookup() to do the real work. If an error occurs, 779 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 780 * we do not have to dereference anything before returning. 781 * In either case ni_startdir will be dereferenced and NULLed 782 * out. 783 */ 784 if (vfslocked) 785 ndp->ni_cnd.cn_flags |= GIANTHELD; 786 error = lookup(ndp); 787 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 788 ndp->ni_cnd.cn_flags &= ~GIANTHELD; 789 if (error) 790 break; 791 792 /* 793 * Check for encountering a symbolic link. Trivial 794 * termination occurs if no symlink encountered. 795 * Note: zfree is safe because error is 0, so we will 796 * not zfree it again when we break. 797 */ 798 if ((cnp->cn_flags & ISSYMLINK) == 0) { 799 if (cnp->cn_flags & (SAVENAME | SAVESTART)) 800 cnp->cn_flags |= HASBUF; 801 else 802 uma_zfree(namei_zone, cnp->cn_pnbuf); 803 if (ndp->ni_vp && !lockleaf) 804 VOP_UNLOCK(ndp->ni_vp, 0, td); 805 break; 806 } 807 808 /* 809 * Validate symlink 810 */ 811 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 812 VOP_UNLOCK(ndp->ni_dvp, 0, td); 813 if (!pubflag) { 814 error = EINVAL; 815 goto badlink2; 816 } 817 818 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 819 error = ELOOP; 820 goto badlink2; 821 } 822 if (ndp->ni_pathlen > 1) 823 cp = uma_zalloc(namei_zone, M_WAITOK); 824 else 825 cp = cnp->cn_pnbuf; 826 aiov.iov_base = cp; 827 aiov.iov_len = MAXPATHLEN; 828 auio.uio_iov = &aiov; 829 auio.uio_iovcnt = 1; 830 auio.uio_offset = 0; 831 auio.uio_rw = UIO_READ; 832 auio.uio_segflg = UIO_SYSSPACE; 833 auio.uio_td = NULL; 834 auio.uio_resid = MAXPATHLEN; 835 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 836 if (error) { 837 badlink1: 838 if (ndp->ni_pathlen > 1) 839 uma_zfree(namei_zone, cp); 840 badlink2: 841 vput(ndp->ni_vp); 842 vrele(ndp->ni_dvp); 843 break; 844 } 845 linklen = MAXPATHLEN - auio.uio_resid; 846 if (linklen == 0) { 847 error = ENOENT; 848 goto badlink1; 849 } 850 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 851 error = ENAMETOOLONG; 852 goto badlink1; 853 } 854 855 /* 856 * Adjust or replace path 857 */ 858 if (ndp->ni_pathlen > 1) { 859 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 860 uma_zfree(namei_zone, cnp->cn_pnbuf); 861 cnp->cn_pnbuf = cp; 862 } else 863 cnp->cn_pnbuf[linklen] = '\0'; 864 ndp->ni_pathlen += linklen; 865 866 /* 867 * Cleanup refs for next loop and check if root directory 868 * should replace current directory. Normally ni_dvp 869 * becomes the new base directory and is cleaned up when 870 * we loop. Explicitly null pointers after invalidation 871 * to clarify operation. 872 */ 873 vput(ndp->ni_vp); 874 ndp->ni_vp = NULL; 875 876 if (cnp->cn_pnbuf[0] == '/') { 877 vrele(ndp->ni_dvp); 878 ndp->ni_dvp = ndp->ni_rootdir; 879 VREF(ndp->ni_dvp); 880 } 881 ndp->ni_startdir = ndp->ni_dvp; 882 ndp->ni_dvp = NULL; 883 } 884 if (!lockleaf) 885 cnp->cn_flags &= ~LOCKLEAF; 886 if (cnp->cn_flags & GIANTHELD) { 887 mtx_unlock(&Giant); 888 cnp->cn_flags &= ~GIANTHELD; 889 } 890 891 /* 892 * nfs_namei() guarentees that fields will not contain garbage 893 * whether an error occurs or not. This allows the caller to track 894 * cleanup state trivially. 895 */ 896out: 897 if (error) { 898 uma_zfree(namei_zone, cnp->cn_pnbuf); 899 ndp->ni_vp = NULL; 900 ndp->ni_dvp = NULL; 901 ndp->ni_startdir = NULL; 902 cnp->cn_flags &= ~HASBUF; 903 VFS_UNLOCK_GIANT(vfslocked); 904 vfslocked = 0; 905 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 906 ndp->ni_dvp = NULL; 907 } 908 /* 909 * This differs from normal namei() in that even on failure we may 910 * return with Giant held due to the dirp return. Make sure we only 911 * have not recursed however. The calling code only expects to drop 912 * one acquire. 913 */ 914 if (vfslocked || dvfslocked) 915 ndp->ni_cnd.cn_flags |= GIANTHELD; 916 if (vfslocked && dvfslocked) 917 VFS_UNLOCK_GIANT(vfslocked); 918 return (error); 919} 920 921/* 922 * A fiddled version of m_adj() that ensures null fill to a long 923 * boundary and only trims off the back end 924 */ 925void 926nfsm_adj(struct mbuf *mp, int len, int nul) 927{ 928 struct mbuf *m; 929 int count, i; 930 char *cp; 931 932 /* 933 * Trim from tail. Scan the mbuf chain, 934 * calculating its length and finding the last mbuf. 935 * If the adjustment only affects this mbuf, then just 936 * adjust and return. Otherwise, rescan and truncate 937 * after the remaining size. 938 */ 939 count = 0; 940 m = mp; 941 for (;;) { 942 count += m->m_len; 943 if (m->m_next == NULL) 944 break; 945 m = m->m_next; 946 } 947 if (m->m_len > len) { 948 m->m_len -= len; 949 if (nul > 0) { 950 cp = mtod(m, caddr_t)+m->m_len-nul; 951 for (i = 0; i < nul; i++) 952 *cp++ = '\0'; 953 } 954 return; 955 } 956 count -= len; 957 if (count < 0) 958 count = 0; 959 /* 960 * Correct length for chain is "count". 961 * Find the mbuf with last data, adjust its length, 962 * and toss data from remaining mbufs on chain. 963 */ 964 for (m = mp; m; m = m->m_next) { 965 if (m->m_len >= count) { 966 m->m_len = count; 967 if (nul > 0) { 968 cp = mtod(m, caddr_t)+m->m_len-nul; 969 for (i = 0; i < nul; i++) 970 *cp++ = '\0'; 971 } 972 if (m->m_next != NULL) { 973 m_freem(m->m_next); 974 m->m_next = NULL; 975 } 976 break; 977 } 978 count -= m->m_len; 979 } 980} 981 982/* 983 * Make these functions instead of macros, so that the kernel text size 984 * doesn't get too big... 985 */ 986void 987nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 988 struct vattr *before_vap, int after_ret, struct vattr *after_vap, 989 struct mbuf **mbp, char **bposp) 990{ 991 struct mbuf *mb = *mbp; 992 char *bpos = *bposp; 993 u_int32_t *tl; 994 995 if (before_ret) { 996 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 997 *tl = nfsrv_nfs_false; 998 } else { 999 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 1000 *tl++ = nfsrv_nfs_true; 1001 txdr_hyper(before_vap->va_size, tl); 1002 tl += 2; 1003 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1004 tl += 2; 1005 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1006 } 1007 *bposp = bpos; 1008 *mbp = mb; 1009 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1010} 1011 1012void 1013nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 1014 struct vattr *after_vap, struct mbuf **mbp, char **bposp) 1015{ 1016 struct mbuf *mb = *mbp; 1017 char *bpos = *bposp; 1018 u_int32_t *tl; 1019 struct nfs_fattr *fp; 1020 1021 if (after_ret) { 1022 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 1023 *tl = nfsrv_nfs_false; 1024 } else { 1025 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1026 *tl++ = nfsrv_nfs_true; 1027 fp = (struct nfs_fattr *)tl; 1028 nfsm_srvfattr(nfsd, after_vap, fp); 1029 } 1030 *mbp = mb; 1031 *bposp = bpos; 1032} 1033 1034void 1035nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 1036 struct nfs_fattr *fp) 1037{ 1038 1039 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1040 fp->fa_uid = txdr_unsigned(vap->va_uid); 1041 fp->fa_gid = txdr_unsigned(vap->va_gid); 1042 if (nfsd->nd_flag & ND_NFSV3) { 1043 fp->fa_type = vtonfsv3_type(vap->va_type); 1044 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1045 txdr_hyper(vap->va_size, &fp->fa3_size); 1046 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1047 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 1048 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 1049 fp->fa3_fsid.nfsuquad[0] = 0; 1050 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1051 fp->fa3_fileid.nfsuquad[0] = 0; 1052 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1053 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1054 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1055 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1056 } else { 1057 fp->fa_type = vtonfsv2_type(vap->va_type); 1058 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1059 fp->fa2_size = txdr_unsigned(vap->va_size); 1060 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1061 if (vap->va_type == VFIFO) 1062 fp->fa2_rdev = 0xffffffff; 1063 else 1064 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1065 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1066 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1067 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1068 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1069 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1070 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1071 } 1072} 1073 1074/* 1075 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1076 * - look up fsid in mount list (if not found ret error) 1077 * - get vp and export rights by calling VFS_FHTOVP() 1078 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1079 * - if not lockflag unlock it with VOP_UNLOCK() 1080 */ 1081int 1082nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp, 1083 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 1084 int *rdonlyp, int pubflag) 1085{ 1086 struct thread *td = curthread; /* XXX */ 1087 struct mount *mp; 1088 int i; 1089 struct ucred *credanon; 1090 int error, exflags; 1091#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1092 struct sockaddr_int *saddr; 1093#endif 1094 int vfslocked; 1095 1096 *vfslockedp = 0; 1097 *vpp = NULL; 1098 1099 if (nfs_ispublicfh(fhp)) { 1100 if (!pubflag || !nfs_pub.np_valid) 1101 return (ESTALE); 1102 fhp = &nfs_pub.np_handle; 1103 } 1104 1105 mp = vfs_getvfs(&fhp->fh_fsid); 1106 if (!mp) 1107 return (ESTALE); 1108 vfslocked = VFS_LOCK_GIANT(mp); 1109 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1110 if (error) 1111 goto out; 1112 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1113 if (error) 1114 goto out; 1115#ifdef MNT_EXNORESPORT 1116 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1117 saddr = (struct sockaddr_in *)nam; 1118 if ((saddr->sin_family == AF_INET || 1119 saddr->sin_family == AF_INET6) && 1120 /* same code for INET and INET6: sin*_port at same offet */ 1121 ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1122 vput(*vpp); 1123 *vpp = NULL; 1124 error = NFSERR_AUTHERR | AUTH_TOOWEAK; 1125 } 1126 } 1127#endif 1128 /* 1129 * Check/setup credentials. 1130 */ 1131 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1132 cred->cr_uid = credanon->cr_uid; 1133 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1134 cred->cr_groups[i] = credanon->cr_groups[i]; 1135 cred->cr_ngroups = i; 1136 } 1137 if (exflags & MNT_EXRDONLY) 1138 *rdonlyp = 1; 1139 else 1140 *rdonlyp = 0; 1141 1142 if (!lockflag) 1143 VOP_UNLOCK(*vpp, 0, td); 1144out: 1145 vfs_rel(mp); 1146 if (error) { 1147 VFS_UNLOCK_GIANT(vfslocked); 1148 } else 1149 *vfslockedp = vfslocked; 1150 return (error); 1151} 1152 1153 1154/* 1155 * WebNFS: check if a filehandle is a public filehandle. For v3, this 1156 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 1157 * transformed this to all zeroes in both cases, so check for it. 1158 */ 1159int 1160nfs_ispublicfh(fhandle_t *fhp) 1161{ 1162 char *cp = (char *)fhp; 1163 int i; 1164 1165 NFSD_LOCK_DONTCARE(); 1166 1167 for (i = 0; i < NFSX_V3FH; i++) 1168 if (*cp++ != 0) 1169 return (FALSE); 1170 return (TRUE); 1171} 1172 1173/* 1174 * This function compares two net addresses by family and returns TRUE 1175 * if they are the same host. 1176 * If there is any doubt, return FALSE. 1177 * The AF_INET family is handled as a special case so that address mbufs 1178 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1179 */ 1180int 1181netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 1182{ 1183 struct sockaddr_in *inetaddr; 1184 1185 NFSD_LOCK_DONTCARE(); 1186 1187 switch (family) { 1188 case AF_INET: 1189 inetaddr = (struct sockaddr_in *)nam; 1190 if (inetaddr->sin_family == AF_INET && 1191 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1192 return (1); 1193 break; 1194#ifdef INET6 1195 case AF_INET6: 1196 { 1197 register struct sockaddr_in6 *inet6addr1, *inet6addr2; 1198 1199 inet6addr1 = (struct sockaddr_in6 *)nam; 1200 inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 1201 /* XXX - should test sin6_scope_id ? */ 1202 if (inet6addr1->sin6_family == AF_INET6 && 1203 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 1204 &inet6addr2->sin6_addr)) 1205 return (1); 1206 break; 1207 } 1208#endif 1209 default: 1210 break; 1211 }; 1212 return (0); 1213} 1214 1215/* 1216 * Map errnos to NFS error numbers. For Version 3 also filter out error 1217 * numbers not specified for the associated procedure. 1218 */ 1219int 1220nfsrv_errmap(struct nfsrv_descript *nd, int err) 1221{ 1222 const short *defaulterrp, *errp; 1223 int e; 1224 1225 1226 if (nd->nd_flag & ND_NFSV3) { 1227 if (nd->nd_procnum <= NFSPROC_COMMIT) { 1228 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1229 while (*++errp) { 1230 if (*errp == err) 1231 return (err); 1232 else if (*errp > err) 1233 break; 1234 } 1235 return ((int)*defaulterrp); 1236 } else 1237 return (err & 0xffff); 1238 } 1239 e = 0; 1240 if (err <= ELAST) 1241 e = nfsrv_v2errmap[err - 1]; 1242 if (e != 0) 1243 return (e); 1244 return (NFSERR_IO); 1245} 1246 1247/* 1248 * Sort the group list in increasing numerical order. 1249 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1250 * that used to be here.) 1251 */ 1252void 1253nfsrvw_sort(gid_t *list, int num) 1254{ 1255 int i, j; 1256 gid_t v; 1257 1258 /* Insertion sort. */ 1259 for (i = 1; i < num; i++) { 1260 v = list[i]; 1261 /* find correct slot for value v, moving others up */ 1262 for (j = i; --j >= 0 && v < list[j];) 1263 list[j + 1] = list[j]; 1264 list[j + 1] = v; 1265 } 1266} 1267 1268/* 1269 * copy credentials making sure that the result can be compared with bcmp(). 1270 */ 1271void 1272nfsrv_setcred(struct ucred *incred, struct ucred *outcred) 1273{ 1274 int i; 1275 1276 bzero((caddr_t)outcred, sizeof (struct ucred)); 1277 refcount_init(&outcred->cr_ref, 1); 1278 outcred->cr_uid = incred->cr_uid; 1279 outcred->cr_ngroups = incred->cr_ngroups; 1280 for (i = 0; i < incred->cr_ngroups; i++) 1281 outcred->cr_groups[i] = incred->cr_groups[i]; 1282 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 1283} 1284 1285/* 1286 * Helper functions for macros. 1287 */ 1288 1289void 1290nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 1291{ 1292 u_int32_t *tl; 1293 1294 if (v3) { 1295 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1296 *tl++ = txdr_unsigned(NFSX_V3FH); 1297 bcopy(f, tl, NFSX_V3FH); 1298 } else { 1299 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 1300 bcopy(f, tl, NFSX_V2FH); 1301 } 1302} 1303 1304void 1305nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 1306{ 1307 u_int32_t *tl; 1308 1309 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1310 *tl++ = nfsrv_nfs_true; 1311 *tl++ = txdr_unsigned(NFSX_V3FH); 1312 bcopy(f, tl, NFSX_V3FH); 1313} 1314 1315int 1316nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1317{ 1318 u_int32_t *tl; 1319 1320 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1321 if (tl == NULL) 1322 return EBADRPC; 1323 *s = fxdr_unsigned(int32_t, *tl); 1324 if (*s > m || *s <= 0) 1325 return EBADRPC; 1326 return 0; 1327} 1328 1329int 1330nfsm_srvnamesiz_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) 1341 return NFSERR_NAMETOL; 1342 if (*s <= 0) 1343 return EBADRPC; 1344 return 0; 1345} 1346 1347int 1348nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1349{ 1350 u_int32_t *tl; 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) 1366{ 1367 struct mbuf *nmp; 1368 1369 NFSD_UNLOCK_ASSERT(); 1370 1371 if (*bp >= *be) { 1372 if (*mp == mb) 1373 (*mp)->m_len += *bp - bpos; 1374 MGET(nmp, M_TRYWAIT, MT_DATA); 1375 MCLGET(nmp, M_TRYWAIT); 1376 nmp->m_len = NFSMSIZ(nmp); 1377 (*mp)->m_next = nmp; 1378 *mp = nmp; 1379 *bp = mtod(*mp, caddr_t); 1380 *be = *bp + (*mp)->m_len; 1381 } 1382 *tl = (u_int32_t *)*bp; 1383} 1384 1385int 1386nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 1387 caddr_t *dpos) 1388{ 1389 u_int32_t *tl; 1390 int fhlen; 1391 1392 if (nfsd->nd_flag & ND_NFSV3) { 1393 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1394 if (tl == NULL) 1395 return EBADRPC; 1396 fhlen = fxdr_unsigned(int, *tl); 1397 if (fhlen != 0 && fhlen != NFSX_V3FH) 1398 return EBADRPC; 1399 } else { 1400 fhlen = NFSX_V2FH; 1401 } 1402 if (fhlen != 0) { 1403 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos); 1404 if (tl == NULL) 1405 return EBADRPC; 1406 bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 1407 } else { 1408 bzero((caddr_t)(f), NFSX_V3FH); 1409 } 1410 return 0; 1411} 1412 1413int 1414nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 1415{ 1416 u_int32_t *tl; 1417 int toclient = 0; 1418 1419 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1420 if (tl == NULL) 1421 return EBADRPC; 1422 if (*tl == nfsrv_nfs_true) { 1423 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1424 if (tl == NULL) 1425 return EBADRPC; 1426 (a)->va_mode = nfstov_mode(*tl); 1427 } 1428 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1429 if (tl == NULL) 1430 return EBADRPC; 1431 if (*tl == nfsrv_nfs_true) { 1432 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1433 if (tl == NULL) 1434 return EBADRPC; 1435 (a)->va_uid = fxdr_unsigned(uid_t, *tl); 1436 } 1437 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1438 if (tl == NULL) 1439 return EBADRPC; 1440 if (*tl == nfsrv_nfs_true) { 1441 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1442 if (tl == NULL) 1443 return EBADRPC; 1444 (a)->va_gid = fxdr_unsigned(gid_t, *tl); 1445 } 1446 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1447 if (tl == NULL) 1448 return EBADRPC; 1449 if (*tl == nfsrv_nfs_true) { 1450 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 1451 if (tl == NULL) 1452 return EBADRPC; 1453 (a)->va_size = fxdr_hyper(tl); 1454 } 1455 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1456 if (tl == NULL) 1457 return EBADRPC; 1458 switch (fxdr_unsigned(int, *tl)) { 1459 case NFSV3SATTRTIME_TOCLIENT: 1460 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 1461 if (tl == NULL) 1462 return EBADRPC; 1463 fxdr_nfsv3time(tl, &(a)->va_atime); 1464 toclient = 1; 1465 break; 1466 case NFSV3SATTRTIME_TOSERVER: 1467 getnanotime(&(a)->va_atime); 1468 a->va_vaflags |= VA_UTIMES_NULL; 1469 break; 1470 } 1471 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1472 if (tl == NULL) 1473 return EBADRPC; 1474 switch (fxdr_unsigned(int, *tl)) { 1475 case NFSV3SATTRTIME_TOCLIENT: 1476 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 1477 if (tl == NULL) 1478 return EBADRPC; 1479 fxdr_nfsv3time(tl, &(a)->va_mtime); 1480 a->va_vaflags &= ~VA_UTIMES_NULL; 1481 break; 1482 case NFSV3SATTRTIME_TOSERVER: 1483 getnanotime(&(a)->va_mtime); 1484 if (toclient == 0) 1485 a->va_vaflags |= VA_UTIMES_NULL; 1486 break; 1487 } 1488 return 0; 1489} 1490