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