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