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