nfs_srvsubs.c revision 84002
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 84002 2001-09-27 02:33:36Z peter $ 38 */ 39 40#include <sys/cdefs.h> 41__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 84002 2001-09-27 02:33:36Z peter $"); 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 <sys/param.h> 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/bio.h> 53#include <sys/buf.h> 54#include <sys/proc.h> 55#include <sys/mount.h> 56#include <sys/vnode.h> 57#include <sys/namei.h> 58#include <sys/mbuf.h> 59#include <sys/socket.h> 60#include <sys/stat.h> 61#include <sys/malloc.h> 62#include <sys/module.h> 63#include <sys/sysent.h> 64#include <sys/syscall.h> 65#include <sys/sysproto.h> 66 67#include <vm/vm.h> 68#include <vm/vm_object.h> 69#include <vm/vm_extern.h> 70#include <vm/vm_zone.h> 71 72#include <nfs/rpcv2.h> 73#include <nfs/nfsproto.h> 74#include <nfsserver/nfs.h> 75#include <nfs/xdr_subs.h> 76#include <nfsserver/nfsm_subs.h> 77 78#include <netinet/in.h> 79 80/* 81 * Data items converted to xdr at startup, since they are constant 82 * This is kinda hokey, but may save a little time doing byte swaps 83 */ 84u_int32_t nfs_xdrneg1; 85u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 86 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 87u_int32_t nfs_prog, nfs_true, nfs_false; 88 89/* And other global data */ 90static nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, 91 NFNON, NFCHR, NFNON }; 92#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 93#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 94 95int nfs_ticks; 96 97struct nfssvc_sockhead nfssvc_sockhead; 98int nfssvc_sockhead_flag; 99struct nfsd_head nfsd_head; 100int nfsd_head_flag; 101 102static int nfs_prev_nfssvc_sy_narg; 103static sy_call_t *nfs_prev_nfssvc_sy_call; 104 105/* 106 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 107 */ 108int nfsv3_procid[NFS_NPROCS] = { 109 NFSPROC_NULL, 110 NFSPROC_GETATTR, 111 NFSPROC_SETATTR, 112 NFSPROC_NOOP, 113 NFSPROC_LOOKUP, 114 NFSPROC_READLINK, 115 NFSPROC_READ, 116 NFSPROC_NOOP, 117 NFSPROC_WRITE, 118 NFSPROC_CREATE, 119 NFSPROC_REMOVE, 120 NFSPROC_RENAME, 121 NFSPROC_LINK, 122 NFSPROC_SYMLINK, 123 NFSPROC_MKDIR, 124 NFSPROC_RMDIR, 125 NFSPROC_READDIR, 126 NFSPROC_FSSTAT, 127 NFSPROC_NOOP, 128 NFSPROC_NOOP, 129 NFSPROC_NOOP, 130 NFSPROC_NOOP, 131 NFSPROC_NOOP, 132}; 133 134/* 135 * and the reverse mapping from generic to Version 2 procedure numbers 136 */ 137int nfsrvv2_procid[NFS_NPROCS] = { 138 NFSV2PROC_NULL, 139 NFSV2PROC_GETATTR, 140 NFSV2PROC_SETATTR, 141 NFSV2PROC_LOOKUP, 142 NFSV2PROC_NOOP, 143 NFSV2PROC_READLINK, 144 NFSV2PROC_READ, 145 NFSV2PROC_WRITE, 146 NFSV2PROC_CREATE, 147 NFSV2PROC_MKDIR, 148 NFSV2PROC_SYMLINK, 149 NFSV2PROC_CREATE, 150 NFSV2PROC_REMOVE, 151 NFSV2PROC_RMDIR, 152 NFSV2PROC_RENAME, 153 NFSV2PROC_LINK, 154 NFSV2PROC_READDIR, 155 NFSV2PROC_NOOP, 156 NFSV2PROC_STATFS, 157 NFSV2PROC_NOOP, 158 NFSV2PROC_NOOP, 159 NFSV2PROC_NOOP, 160 NFSV2PROC_NOOP, 161}; 162 163/* 164 * Maps errno values to nfs error numbers. 165 * Use NFSERR_IO as the catch all for ones not specifically defined in 166 * RFC 1094. 167 */ 168static u_char nfsrv_v2errmap[ELAST] = { 169 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 170 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 171 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 172 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 173 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 174 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 175 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 176 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 177 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 178 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 179 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 180 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 181 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 182 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 183 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 184 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 185 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 186 NFSERR_IO /* << Last is 86 */ 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 rpc_vers = txdr_unsigned(RPC_VER2); 531 rpc_call = txdr_unsigned(RPC_CALL); 532 rpc_reply = txdr_unsigned(RPC_REPLY); 533 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 534 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 535 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 536 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 537 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 538 nfs_prog = txdr_unsigned(NFS_PROG); 539 nfs_true = txdr_unsigned(TRUE); 540 nfs_false = txdr_unsigned(FALSE); 541 nfs_xdrneg1 = txdr_unsigned(-1); 542 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 543 if (nfs_ticks < 1) 544 nfs_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 = (struct vnode *)0; 607 cnp->cn_pnbuf = zalloc(namei_zone); 608 609 /* 610 * Copy the name from the mbuf list to ndp->ni_pnbuf 611 * and set the various ndp fields appropriately. 612 */ 613 fromcp = *dposp; 614 tocp = cnp->cn_pnbuf; 615 md = *mdp; 616 rem = mtod(md, caddr_t) + md->m_len - fromcp; 617 for (i = 0; i < len; i++) { 618 while (rem == 0) { 619 md = md->m_next; 620 if (md == NULL) { 621 error = EBADRPC; 622 goto out; 623 } 624 fromcp = mtod(md, caddr_t); 625 rem = md->m_len; 626 } 627 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 628 error = EACCES; 629 goto out; 630 } 631 *tocp++ = *fromcp++; 632 rem--; 633 } 634 *tocp = '\0'; 635 *mdp = md; 636 *dposp = fromcp; 637 len = nfsm_rndup(len)-len; 638 if (len > 0) { 639 if (rem >= len) 640 *dposp += len; 641 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 642 goto out; 643 } 644 645 /* 646 * Extract and set starting directory. 647 */ 648 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 649 nam, &rdonly, pubflag); 650 if (error) 651 goto out; 652 if (dp->v_type != VDIR) { 653 vrele(dp); 654 error = ENOTDIR; 655 goto out; 656 } 657 658 if (rdonly) 659 cnp->cn_flags |= RDONLY; 660 661 /* 662 * Set return directory. Reference to dp is implicitly transfered 663 * to the returned pointer 664 */ 665 *retdirp = dp; 666 667 if (pubflag) { 668 /* 669 * Oh joy. For WebNFS, handle those pesky '%' escapes, 670 * and the 'native path' indicator. 671 */ 672 cp = zalloc(namei_zone); 673 fromcp = cnp->cn_pnbuf; 674 tocp = cp; 675 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 676 switch ((unsigned char)*fromcp) { 677 case WEBNFS_NATIVE_CHAR: 678 /* 679 * 'Native' path for us is the same 680 * as a path according to the NFS spec, 681 * just skip the escape char. 682 */ 683 fromcp++; 684 break; 685 /* 686 * More may be added in the future, range 0x80-0xff 687 */ 688 default: 689 error = EIO; 690 zfree(namei_zone, cp); 691 goto out; 692 } 693 } 694 /* 695 * Translate the '%' escapes, URL-style. 696 */ 697 while (*fromcp != '\0') { 698 if (*fromcp == WEBNFS_ESC_CHAR) { 699 if (fromcp[1] != '\0' && fromcp[2] != '\0') { 700 fromcp++; 701 *tocp++ = HEXSTRTOI(fromcp); 702 fromcp += 2; 703 continue; 704 } else { 705 error = ENOENT; 706 zfree(namei_zone, cp); 707 goto out; 708 } 709 } else 710 *tocp++ = *fromcp++; 711 } 712 *tocp = '\0'; 713 zfree(namei_zone, cnp->cn_pnbuf); 714 cnp->cn_pnbuf = cp; 715 } 716 717 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 718 ndp->ni_segflg = UIO_SYSSPACE; 719 720 if (pubflag) { 721 ndp->ni_rootdir = rootvnode; 722 ndp->ni_loopcnt = 0; 723 if (cnp->cn_pnbuf[0] == '/') 724 dp = rootvnode; 725 } else { 726 cnp->cn_flags |= NOCROSSMOUNT; 727 } 728 729 /* 730 * Initialize for scan, set ni_startdir and bump ref on dp again 731 * becuase lookup() will dereference ni_startdir. 732 */ 733 734 cnp->cn_thread = td; 735 VREF(dp); 736 ndp->ni_startdir = dp; 737 738 for (;;) { 739 cnp->cn_nameptr = cnp->cn_pnbuf; 740 /* 741 * Call lookup() to do the real work. If an error occurs, 742 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 743 * we do not have to dereference anything before returning. 744 * In either case ni_startdir will be dereferenced and NULLed 745 * out. 746 */ 747 error = lookup(ndp); 748 if (error) 749 break; 750 751 /* 752 * Check for encountering a symbolic link. Trivial 753 * termination occurs if no symlink encountered. 754 * Note: zfree is safe because error is 0, so we will 755 * not zfree it again when we break. 756 */ 757 if ((cnp->cn_flags & ISSYMLINK) == 0) { 758 nfsrv_object_create(ndp->ni_vp); 759 if (cnp->cn_flags & (SAVENAME | SAVESTART)) 760 cnp->cn_flags |= HASBUF; 761 else 762 zfree(namei_zone, cnp->cn_pnbuf); 763 break; 764 } 765 766 /* 767 * Validate symlink 768 */ 769 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 770 VOP_UNLOCK(ndp->ni_dvp, 0, td); 771 if (!pubflag) { 772 error = EINVAL; 773 goto badlink2; 774 } 775 776 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 777 error = ELOOP; 778 goto badlink2; 779 } 780 if (ndp->ni_pathlen > 1) 781 cp = zalloc(namei_zone); 782 else 783 cp = cnp->cn_pnbuf; 784 aiov.iov_base = cp; 785 aiov.iov_len = MAXPATHLEN; 786 auio.uio_iov = &aiov; 787 auio.uio_iovcnt = 1; 788 auio.uio_offset = 0; 789 auio.uio_rw = UIO_READ; 790 auio.uio_segflg = UIO_SYSSPACE; 791 auio.uio_td = (struct thread *)0; 792 auio.uio_resid = MAXPATHLEN; 793 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 794 if (error) { 795 badlink1: 796 if (ndp->ni_pathlen > 1) 797 zfree(namei_zone, cp); 798 badlink2: 799 vrele(ndp->ni_dvp); 800 vput(ndp->ni_vp); 801 break; 802 } 803 linklen = MAXPATHLEN - auio.uio_resid; 804 if (linklen == 0) { 805 error = ENOENT; 806 goto badlink1; 807 } 808 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 809 error = ENAMETOOLONG; 810 goto badlink1; 811 } 812 813 /* 814 * Adjust or replace path 815 */ 816 if (ndp->ni_pathlen > 1) { 817 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 818 zfree(namei_zone, cnp->cn_pnbuf); 819 cnp->cn_pnbuf = cp; 820 } else 821 cnp->cn_pnbuf[linklen] = '\0'; 822 ndp->ni_pathlen += linklen; 823 824 /* 825 * Cleanup refs for next loop and check if root directory 826 * should replace current directory. Normally ni_dvp 827 * becomes the new base directory and is cleaned up when 828 * we loop. Explicitly null pointers after invalidation 829 * to clarify operation. 830 */ 831 vput(ndp->ni_vp); 832 ndp->ni_vp = NULL; 833 834 if (cnp->cn_pnbuf[0] == '/') { 835 vrele(ndp->ni_dvp); 836 ndp->ni_dvp = ndp->ni_rootdir; 837 VREF(ndp->ni_dvp); 838 } 839 ndp->ni_startdir = ndp->ni_dvp; 840 ndp->ni_dvp = NULL; 841 } 842 843 /* 844 * nfs_namei() guarentees that fields will not contain garbage 845 * whether an error occurs or not. This allows the caller to track 846 * cleanup state trivially. 847 */ 848out: 849 if (error) { 850 zfree(namei_zone, cnp->cn_pnbuf); 851 ndp->ni_vp = NULL; 852 ndp->ni_dvp = NULL; 853 ndp->ni_startdir = NULL; 854 cnp->cn_flags &= ~HASBUF; 855 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 856 ndp->ni_dvp = NULL; 857 } 858 return (error); 859} 860 861/* 862 * A fiddled version of m_adj() that ensures null fill to a long 863 * boundary and only trims off the back end 864 */ 865void 866nfsm_adj(struct mbuf *mp, int len, int nul) 867{ 868 struct mbuf *m; 869 int count, i; 870 char *cp; 871 872 /* 873 * Trim from tail. Scan the mbuf chain, 874 * calculating its length and finding the last mbuf. 875 * If the adjustment only affects this mbuf, then just 876 * adjust and return. Otherwise, rescan and truncate 877 * after the remaining size. 878 */ 879 count = 0; 880 m = mp; 881 for (;;) { 882 count += m->m_len; 883 if (m->m_next == (struct mbuf *)0) 884 break; 885 m = m->m_next; 886 } 887 if (m->m_len > len) { 888 m->m_len -= len; 889 if (nul > 0) { 890 cp = mtod(m, caddr_t)+m->m_len-nul; 891 for (i = 0; i < nul; i++) 892 *cp++ = '\0'; 893 } 894 return; 895 } 896 count -= len; 897 if (count < 0) 898 count = 0; 899 /* 900 * Correct length for chain is "count". 901 * Find the mbuf with last data, adjust its length, 902 * and toss data from remaining mbufs on chain. 903 */ 904 for (m = mp; m; m = m->m_next) { 905 if (m->m_len >= count) { 906 m->m_len = count; 907 if (nul > 0) { 908 cp = mtod(m, caddr_t)+m->m_len-nul; 909 for (i = 0; i < nul; i++) 910 *cp++ = '\0'; 911 } 912 break; 913 } 914 count -= m->m_len; 915 } 916 for (m = m->m_next;m;m = m->m_next) 917 m->m_len = 0; 918} 919 920/* 921 * Make these functions instead of macros, so that the kernel text size 922 * doesn't get too big... 923 */ 924void 925nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 926 struct vattr *before_vap, int after_ret, struct vattr *after_vap, 927 struct mbuf **mbp, char **bposp) 928{ 929 struct mbuf *mb = *mbp; 930 char *bpos = *bposp; 931 u_int32_t *tl; 932 933 if (before_ret) { 934 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 935 *tl = nfs_false; 936 } else { 937 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 938 *tl++ = nfs_true; 939 txdr_hyper(before_vap->va_size, tl); 940 tl += 2; 941 txdr_nfsv3time(&(before_vap->va_mtime), tl); 942 tl += 2; 943 txdr_nfsv3time(&(before_vap->va_ctime), tl); 944 } 945 *bposp = bpos; 946 *mbp = mb; 947 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 948} 949 950void 951nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 952 struct vattr *after_vap, struct mbuf **mbp, char **bposp) 953{ 954 struct mbuf *mb = *mbp; 955 char *bpos = *bposp; 956 u_int32_t *tl; 957 struct nfs_fattr *fp; 958 959 if (after_ret) { 960 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 961 *tl = nfs_false; 962 } else { 963 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 964 *tl++ = nfs_true; 965 fp = (struct nfs_fattr *)tl; 966 nfsm_srvfattr(nfsd, after_vap, fp); 967 } 968 *mbp = mb; 969 *bposp = bpos; 970} 971 972void 973nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 974 struct nfs_fattr *fp) 975{ 976 977 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 978 fp->fa_uid = txdr_unsigned(vap->va_uid); 979 fp->fa_gid = txdr_unsigned(vap->va_gid); 980 if (nfsd->nd_flag & ND_NFSV3) { 981 fp->fa_type = vtonfsv3_type(vap->va_type); 982 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 983 txdr_hyper(vap->va_size, &fp->fa3_size); 984 txdr_hyper(vap->va_bytes, &fp->fa3_used); 985 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 986 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 987 fp->fa3_fsid.nfsuquad[0] = 0; 988 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 989 fp->fa3_fileid.nfsuquad[0] = 0; 990 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 991 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 992 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 993 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 994 } else { 995 fp->fa_type = vtonfsv2_type(vap->va_type); 996 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 997 fp->fa2_size = txdr_unsigned(vap->va_size); 998 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 999 if (vap->va_type == VFIFO) 1000 fp->fa2_rdev = 0xffffffff; 1001 else 1002 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1003 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1004 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1005 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1006 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1007 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1008 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1009 } 1010} 1011 1012/* 1013 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1014 * - look up fsid in mount list (if not found ret error) 1015 * - get vp and export rights by calling VFS_FHTOVP() 1016 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1017 * - if not lockflag unlock it with VOP_UNLOCK() 1018 */ 1019int 1020nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 1021 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 1022 int *rdonlyp, int pubflag) 1023{ 1024 struct thread *td = curthread; /* XXX */ 1025 struct mount *mp; 1026 int i; 1027 struct ucred *credanon; 1028 int error, exflags; 1029#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 1030 struct sockaddr_int *saddr; 1031#endif 1032 1033 *vpp = (struct vnode *)0; 1034 1035 if (nfs_ispublicfh(fhp)) { 1036 if (!pubflag || !nfs_pub.np_valid) 1037 return (ESTALE); 1038 fhp = &nfs_pub.np_handle; 1039 } 1040 1041 mp = vfs_getvfs(&fhp->fh_fsid); 1042 if (!mp) 1043 return (ESTALE); 1044 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1045 if (error) 1046 return (error); 1047 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1048 if (error) 1049 return (error); 1050#ifdef MNT_EXNORESPORT 1051 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 1052 saddr = (struct sockaddr_in *)nam; 1053 if (saddr->sin_family == AF_INET && 1054 ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1055 vput(*vpp); 1056 *vpp = NULL; 1057 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1058 } 1059 } 1060#endif 1061 /* 1062 * Check/setup credentials. 1063 */ 1064 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1065 cred->cr_uid = credanon->cr_uid; 1066 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1067 cred->cr_groups[i] = credanon->cr_groups[i]; 1068 cred->cr_ngroups = i; 1069 } 1070 if (exflags & MNT_EXRDONLY) 1071 *rdonlyp = 1; 1072 else 1073 *rdonlyp = 0; 1074 1075 nfsrv_object_create(*vpp); 1076 1077 if (!lockflag) 1078 VOP_UNLOCK(*vpp, 0, td); 1079 return (0); 1080} 1081 1082 1083/* 1084 * WebNFS: check if a filehandle is a public filehandle. For v3, this 1085 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 1086 * transformed this to all zeroes in both cases, so check for it. 1087 */ 1088int 1089nfs_ispublicfh(fhandle_t *fhp) 1090{ 1091 char *cp = (char *)fhp; 1092 int i; 1093 1094 for (i = 0; i < NFSX_V3FH; i++) 1095 if (*cp++ != 0) 1096 return (FALSE); 1097 return (TRUE); 1098} 1099 1100/* 1101 * This function compares two net addresses by family and returns TRUE 1102 * if they are the same host. 1103 * If there is any doubt, return FALSE. 1104 * The AF_INET family is handled as a special case so that address mbufs 1105 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1106 */ 1107int 1108netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 1109{ 1110 struct sockaddr_in *inetaddr; 1111 1112 switch (family) { 1113 case AF_INET: 1114 inetaddr = (struct sockaddr_in *)nam; 1115 if (inetaddr->sin_family == AF_INET && 1116 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1117 return (1); 1118 break; 1119 default: 1120 break; 1121 }; 1122 return (0); 1123} 1124 1125/* 1126 * Map errnos to NFS error numbers. For Version 3 also filter out error 1127 * numbers not specified for the associated procedure. 1128 */ 1129int 1130nfsrv_errmap(struct nfsrv_descript *nd, int err) 1131{ 1132 short *defaulterrp, *errp; 1133 1134 if (nd->nd_flag & ND_NFSV3) { 1135 if (nd->nd_procnum <= NFSPROC_COMMIT) { 1136 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1137 while (*++errp) { 1138 if (*errp == err) 1139 return (err); 1140 else if (*errp > err) 1141 break; 1142 } 1143 return ((int)*defaulterrp); 1144 } else 1145 return (err & 0xffff); 1146 } 1147 if (err <= ELAST) 1148 return ((int)nfsrv_v2errmap[err - 1]); 1149 return (NFSERR_IO); 1150} 1151 1152int 1153nfsrv_object_create(struct vnode *vp) 1154{ 1155 1156 if (vp == NULL || vp->v_type != VREG) 1157 return (1); 1158 return (vfs_object_create(vp, curthread, 1159 curthread ? curthread->td_proc->p_ucred : NULL)); 1160} 1161 1162/* 1163 * Sort the group list in increasing numerical order. 1164 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1165 * that used to be here.) 1166 */ 1167void 1168nfsrvw_sort(gid_t *list, int num) 1169{ 1170 int i, j; 1171 gid_t v; 1172 1173 /* Insertion sort. */ 1174 for (i = 1; i < num; i++) { 1175 v = list[i]; 1176 /* find correct slot for value v, moving others up */ 1177 for (j = i; --j >= 0 && v < list[j];) 1178 list[j + 1] = list[j]; 1179 list[j + 1] = v; 1180 } 1181} 1182 1183/* 1184 * copy credentials making sure that the result can be compared with bcmp(). 1185 */ 1186void 1187nfsrv_setcred(struct ucred *incred, struct ucred *outcred) 1188{ 1189 int i; 1190 1191 bzero((caddr_t)outcred, sizeof (struct ucred)); 1192 outcred->cr_ref = 1; 1193 outcred->cr_uid = incred->cr_uid; 1194 outcred->cr_ngroups = incred->cr_ngroups; 1195 for (i = 0; i < incred->cr_ngroups; i++) 1196 outcred->cr_groups[i] = incred->cr_groups[i]; 1197 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 1198} 1199 1200/* 1201 * Helper functions for macros. 1202 */ 1203 1204void 1205nfsm_srvfhtom_xx(fhandle_t *f, int v3, 1206 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 1207{ 1208 u_int32_t *cp; 1209 1210 if (v3) { 1211 *tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1212 *(*tl)++ = txdr_unsigned(NFSX_V3FH); 1213 bcopy(f, (*tl), NFSX_V3FH); 1214 } else { 1215 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 1216 bcopy(f, cp, NFSX_V2FH); 1217 } 1218} 1219 1220void 1221nfsm_srvpostop_fh_xx(fhandle_t *f, 1222 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 1223{ 1224 1225 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 1226 *(*tl)++ = nfs_true; 1227 *(*tl)++ = txdr_unsigned(NFSX_V3FH); 1228 bcopy(f, (*tl), NFSX_V3FH); 1229} 1230 1231int 1232nfsm_srvstrsiz_xx(int *s, int m, 1233 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 1234{ 1235 int ret; 1236 1237 ret = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1238 if (ret) 1239 return ret; 1240 *s = fxdr_unsigned(int32_t, **tl); 1241 if (*s > m || *s <= 0) 1242 return EBADRPC; 1243 return 0; 1244} 1245 1246int 1247nfsm_srvnamesiz_xx(int *s, 1248 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 1249{ 1250 int ret; 1251 1252 ret = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1253 if (ret) 1254 return ret; 1255 *s = fxdr_unsigned(int32_t, **tl); 1256 if (*s > NFS_MAXNAMLEN) 1257 return NFSERR_NAMETOL; 1258 if (*s <= 0) 1259 return EBADRPC; 1260 return 0; 1261} 1262 1263void 1264nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 1265 char **bp, char **be, caddr_t bpos) 1266{ 1267 struct mbuf *nmp; 1268 1269 if (*bp >= *be) { 1270 if (*mp == mb) 1271 (*mp)->m_len += *bp - bpos; 1272 MGET(nmp, M_TRYWAIT, MT_DATA); 1273 MCLGET(nmp, M_TRYWAIT); 1274 nmp->m_len = NFSMSIZ(nmp); 1275 (*mp)->m_next = nmp; 1276 *mp = nmp; 1277 *bp = mtod(*mp, caddr_t); 1278 *be = *bp + (*mp)->m_len; 1279 } 1280 *tl = (u_int32_t *)*bp; 1281} 1282 1283int 1284nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, 1285 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 1286{ 1287 int error; 1288 int fhlen; 1289 1290 if (nfsd->nd_flag & ND_NFSV3) { 1291 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1292 if (error) 1293 return error; 1294 fhlen = fxdr_unsigned(int, **tl); 1295 if (fhlen != 0 && fhlen != NFSX_V3FH) 1296 return EBADRPC; 1297 } else { 1298 fhlen = NFSX_V2FH; 1299 } 1300 if (fhlen != 0) { 1301 error = nfsm_dissect_xx((void **)tl, fhlen, md, dpos); 1302 if (error) 1303 return error; 1304 bcopy((caddr_t)*tl, (caddr_t)(f), fhlen); 1305 } else { 1306 bzero((caddr_t)(f), NFSX_V3FH); 1307 } 1308 return 0; 1309} 1310 1311int 1312nfsm_srvsattr_xx(struct vattr *a, 1313 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 1314{ 1315 int error = 0; 1316 1317 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1318 if (error) 1319 goto bugout; 1320 if (**tl == nfs_true) { 1321 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1322 if (error) 1323 goto bugout; 1324 (a)->va_mode = nfstov_mode(**tl); 1325 } 1326 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1327 if (error) 1328 goto bugout; 1329 if (**tl == nfs_true) { 1330 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1331 if (error) 1332 goto bugout; 1333 (a)->va_uid = fxdr_unsigned(uid_t, **tl); 1334 } 1335 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1336 if (error) 1337 goto bugout; 1338 if (**tl == nfs_true) { 1339 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1340 if (error) 1341 goto bugout; 1342 (a)->va_gid = fxdr_unsigned(gid_t, **tl); 1343 } 1344 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1345 if (error) 1346 goto bugout; 1347 if (**tl == nfs_true) { 1348 error = nfsm_dissect_xx((void **)tl, 2 * NFSX_UNSIGNED, 1349 md, dpos); 1350 if (error) 1351 goto bugout; 1352 (a)->va_size = fxdr_hyper(*tl); 1353 } 1354 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1355 if (error) 1356 goto bugout; 1357 switch (fxdr_unsigned(int, **tl)) { 1358 case NFSV3SATTRTIME_TOCLIENT: 1359 error = nfsm_dissect_xx((void **)tl, 2 * NFSX_UNSIGNED, 1360 md, dpos); 1361 if (error) 1362 goto bugout; 1363 fxdr_nfsv3time(*tl, &(a)->va_atime); 1364 break; 1365 case NFSV3SATTRTIME_TOSERVER: 1366 getnanotime(&(a)->va_atime); 1367 break; 1368 } 1369 error = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, md, dpos); 1370 if (error) 1371 goto bugout; 1372 switch (fxdr_unsigned(int, **tl)) { 1373 case NFSV3SATTRTIME_TOCLIENT: 1374 error = nfsm_dissect_xx((void **)tl, 2 * NFSX_UNSIGNED, 1375 md, dpos); 1376 if (error) 1377 goto bugout; 1378 fxdr_nfsv3time(*tl, &(a)->va_mtime); 1379 break; 1380 case NFSV3SATTRTIME_TOSERVER: 1381 getnanotime(&(a)->va_mtime); 1382 break; 1383 } 1384 return 0; 1385 1386bugout: 1387 return error; 1388} 1389 1390void 1391nfs_rephead_xx(int s, struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1392 int error, struct mbuf **mrq, struct mbuf **mb, 1393 struct mbuf **mreq, struct mbuf **mrep, caddr_t *bpos) 1394{ 1395 1396 nfs_rephead(s, nfsd, slp, error, mrq, mb, bpos); 1397 if (*mrep != NULL) { 1398 m_freem(*mrep); 1399 *mrep = NULL; 1400 } 1401 *mreq = *mrq; 1402} 1403