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