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