1 /* 2 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/kern/vfs_nlookup.c,v 1.11 2005/04/19 17:54:42 dillon Exp $ 35 */ 36 /* 37 * nlookup() is the 'new' namei interface. Rather then return directory and 38 * leaf vnodes (in various lock states) the new interface instead deals in 39 * namecache records. Namecache records may represent both a positive or 40 * a negative hit. The namespace is locked via the namecache record instead 41 * of via the vnode, and only the leaf namecache record (representing the 42 * filename) needs to be locked. 43 * 44 * This greatly improves filesystem parallelism and is a huge simplification 45 * of the API verses the old vnode locking / namei scheme. 46 * 47 * Filesystems must actively control the caching aspects of the namecache, 48 * and since namecache pointers are used as handles they are non-optional 49 * even for filesystems which do not generally wish to cache things. It is 50 * intended that a separate cache coherency API will be constructed to handle 51 * these issues. 52 */ 53 54 #include "opt_ktrace.h" 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/kernel.h> 59 #include <sys/vnode.h> 60 #include <sys/mount.h> 61 #include <sys/filedesc.h> 62 #include <sys/proc.h> 63 #include <sys/namei.h> 64 #include <sys/nlookup.h> 65 #include <sys/malloc.h> 66 #include <sys/stat.h> 67 #include <vm/vm_zone.h> 68 69 #ifdef KTRACE 70 #include <sys/ktrace.h> 71 #endif 72 73 /* 74 * Initialize a nlookup() structure, early error return for copyin faults 75 * or a degenerate empty string (which is not allowed). 76 * 77 * The first process proc0's credentials are used if the calling thread 78 * is not associated with a process context. 79 */ 80 int 81 nlookup_init(struct nlookupdata *nd, 82 const char *path, enum uio_seg seg, int flags) 83 { 84 size_t pathlen; 85 struct proc *p; 86 thread_t td; 87 int error; 88 89 td = curthread; 90 p = td->td_proc; 91 92 /* 93 * note: the pathlen set by copy*str() includes the terminating \0. 94 */ 95 bzero(nd, sizeof(struct nlookupdata)); 96 nd->nl_path = zalloc(namei_zone); 97 nd->nl_flags |= NLC_HASBUF; 98 if (seg == UIO_SYSSPACE) 99 error = copystr(path, nd->nl_path, MAXPATHLEN, &pathlen); 100 else 101 error = copyinstr(path, nd->nl_path, MAXPATHLEN, &pathlen); 102 103 /* 104 * Don't allow empty pathnames. 105 * POSIX.1 requirement: "" is not a vaild file name. 106 */ 107 if (error == 0 && pathlen <= 1) 108 error = ENOENT; 109 110 if (error == 0) { 111 if (p && p->p_fd) { 112 nd->nl_ncp = cache_hold(p->p_fd->fd_ncdir); 113 nd->nl_rootncp = cache_hold(p->p_fd->fd_nrdir); 114 if (p->p_fd->fd_njdir) 115 nd->nl_jailncp = cache_hold(p->p_fd->fd_njdir); 116 nd->nl_cred = crhold(p->p_ucred); 117 } else { 118 nd->nl_ncp = cache_hold(rootncp); 119 nd->nl_rootncp = cache_hold(nd->nl_ncp); 120 nd->nl_jailncp = cache_hold(nd->nl_ncp); 121 nd->nl_cred = crhold(proc0.p_ucred); 122 } 123 nd->nl_td = td; 124 nd->nl_flags |= flags; 125 } else { 126 nlookup_done(nd); 127 } 128 return(error); 129 } 130 131 /* 132 * This works similarly to nlookup_init() but does not assume a process 133 * context. rootncp is always chosen for the root directory and the cred 134 * and starting directory are supplied in arguments. 135 */ 136 int 137 nlookup_init_raw(struct nlookupdata *nd, 138 const char *path, enum uio_seg seg, int flags, 139 struct ucred *cred, struct namecache *ncstart) 140 { 141 size_t pathlen; 142 thread_t td; 143 int error; 144 145 td = curthread; 146 147 bzero(nd, sizeof(struct nlookupdata)); 148 nd->nl_path = zalloc(namei_zone); 149 nd->nl_flags |= NLC_HASBUF; 150 if (seg == UIO_SYSSPACE) 151 error = copystr(path, nd->nl_path, MAXPATHLEN, &pathlen); 152 else 153 error = copyinstr(path, nd->nl_path, MAXPATHLEN, &pathlen); 154 155 /* 156 * Don't allow empty pathnames. 157 * POSIX.1 requirement: "" is not a vaild file name. 158 */ 159 if (error == 0 && pathlen <= 1) 160 error = ENOENT; 161 162 if (error == 0) { 163 nd->nl_ncp = cache_hold(ncstart); 164 nd->nl_rootncp = cache_hold(rootncp); 165 nd->nl_jailncp = cache_hold(rootncp); 166 nd->nl_cred = crhold(cred); 167 nd->nl_td = td; 168 nd->nl_flags |= flags; 169 } else { 170 nlookup_done(nd); 171 } 172 return(error); 173 } 174 175 /* 176 * Set a different credential; this credential will be used by future 177 * operations performed on nd.nl_open_vp and nlookupdata structure. 178 */ 179 void 180 nlookup_set_cred(struct nlookupdata *nd, struct ucred *cred) 181 { 182 KKASSERT(nd->nl_cred != NULL); 183 184 if (nd->nl_cred != cred) { 185 cred = crhold(cred); 186 crfree(nd->nl_cred); 187 nd->nl_cred = cred; 188 } 189 } 190 191 /* 192 * Cleanup a nlookupdata structure after we are through with it. This may 193 * be called on any nlookupdata structure initialized with nlookup_init(). 194 * Calling nlookup_done() is mandatory in all cases except where nlookup_init() 195 * returns an error, even if as a consumer you believe you have taken all 196 * dynamic elements out of the nlookupdata structure. 197 */ 198 void 199 nlookup_done(struct nlookupdata *nd) 200 { 201 if (nd->nl_ncp) { 202 if (nd->nl_flags & NLC_NCPISLOCKED) { 203 nd->nl_flags &= ~NLC_NCPISLOCKED; 204 cache_unlock(nd->nl_ncp); 205 } 206 cache_drop(nd->nl_ncp); 207 nd->nl_ncp = NULL; 208 } 209 if (nd->nl_rootncp) { 210 cache_drop(nd->nl_rootncp); 211 nd->nl_rootncp = NULL; 212 } 213 if (nd->nl_jailncp) { 214 cache_drop(nd->nl_jailncp); 215 nd->nl_jailncp = NULL; 216 } 217 if ((nd->nl_flags & NLC_HASBUF) && nd->nl_path) { 218 zfree(namei_zone, nd->nl_path); 219 nd->nl_path = NULL; 220 } 221 if (nd->nl_cred) { 222 crfree(nd->nl_cred); 223 nd->nl_cred = NULL; 224 } 225 if (nd->nl_open_vp) { 226 if (nd->nl_flags & NLC_LOCKVP) { 227 VOP_UNLOCK(nd->nl_open_vp, 0, nd->nl_td); 228 nd->nl_flags &= ~NLC_LOCKVP; 229 } 230 vn_close(nd->nl_open_vp, nd->nl_vp_fmode, nd->nl_td); 231 nd->nl_open_vp = NULL; 232 } 233 nd->nl_flags = 0; /* clear remaining flags (just clear everything) */ 234 } 235 236 void 237 nlookup_zero(struct nlookupdata *nd) 238 { 239 bzero(nd, sizeof(struct nlookupdata)); 240 } 241 242 /* 243 * Simple all-in-one nlookup. Returns a locked namecache structure or NULL 244 * if an error occured. 245 * 246 * Note that the returned ncp is not checked for permissions, though VEXEC 247 * is checked on the directory path leading up to the result. The caller 248 * must call naccess() to check the permissions of the returned leaf. 249 */ 250 struct namecache * 251 nlookup_simple(const char *str, enum uio_seg seg, 252 int niflags, int *error) 253 { 254 struct nlookupdata nd; 255 struct namecache *ncp; 256 257 *error = nlookup_init(&nd, str, seg, niflags); 258 if (*error == 0) { 259 if ((*error = nlookup(&nd)) == 0) { 260 ncp = nd.nl_ncp; /* keep hold ref from structure */ 261 nd.nl_ncp = NULL; /* and NULL out */ 262 } else { 263 ncp = NULL; 264 } 265 nlookup_done(&nd); 266 } else { 267 ncp = NULL; 268 } 269 return(ncp); 270 } 271 272 /* 273 * Do a generic nlookup. Note that the passed nd is not nlookup_done()'d 274 * on return, even if an error occurs. If no error occurs the returned 275 * nl_ncp is always referenced and locked, otherwise it may or may not be. 276 * 277 * Intermediate directory elements, including the current directory, require 278 * execute (search) permission. nlookup does not examine the access 279 * permissions on the returned element. 280 * 281 * If NLC_CREATE or NLC_DELETE is set the last directory must allow node 282 * creation (VCREATE/VDELETE), and an error code of 0 will be returned for 283 * a non-existant target. Otherwise a non-existant target will cause 284 * ENOENT to be returned. 285 */ 286 int 287 nlookup(struct nlookupdata *nd) 288 { 289 struct nlcomponent nlc; 290 struct namecache *ncp; 291 int wasdotordotdot; 292 char *ptr; 293 char *xptr; 294 int error; 295 int len; 296 297 #ifdef KTRACE 298 if (KTRPOINT(nd->nl_td, KTR_NAMEI)) 299 ktrnamei(nd->nl_td->td_proc->p_tracep, nd->nl_path); 300 #endif 301 bzero(&nlc, sizeof(nlc)); 302 303 /* 304 * Setup for the loop. The current working namecache element must 305 * be in a refd + unlocked state. This typically the case on entry except 306 * when stringing nlookup()'s along in a chain, since nlookup() always 307 * returns nl_ncp in a locked state. 308 */ 309 nd->nl_loopcnt = 0; 310 if (nd->nl_flags & NLC_NCPISLOCKED) { 311 nd->nl_flags &= ~NLC_NCPISLOCKED; 312 cache_unlock(nd->nl_ncp); 313 } 314 ptr = nd->nl_path; 315 316 /* 317 * Loop on the path components. At the top of the loop nd->nl_ncp 318 * is ref'd and unlocked and represents our current position. 319 */ 320 for (;;) { 321 /* 322 * Check if the root directory should replace the current 323 * directory. This is done at the start of a translation 324 * or after a symbolic link has been found. In other cases 325 * ptr will never be pointing at a '/'. 326 */ 327 if (*ptr == '/') { 328 do { 329 ++ptr; 330 } while (*ptr == '/'); 331 ncp = cache_hold(nd->nl_rootncp); 332 cache_drop(nd->nl_ncp); 333 nd->nl_ncp = ncp; 334 if (*ptr == 0) { 335 cache_lock(nd->nl_ncp); 336 nd->nl_flags |= NLC_NCPISLOCKED; 337 error = 0; 338 break; 339 } 340 continue; 341 } 342 343 /* 344 * Check directory search permissions 345 */ 346 if ((error = naccess(nd->nl_ncp, VEXEC, nd->nl_cred)) != 0) 347 break; 348 349 /* 350 * Extract the path component 351 */ 352 nlc.nlc_nameptr = ptr; 353 while (*ptr && *ptr != '/') 354 ++ptr; 355 nlc.nlc_namelen = ptr - nlc.nlc_nameptr; 356 357 /* 358 * Lookup the path component in the cache, creating an unresolved 359 * entry if necessary. We have to handle "." and ".." as special 360 * cases. 361 * 362 * When handling ".." we have to detect a traversal back through a 363 * mount point and skip the mount-under node. If we are at the root 364 * ".." just returns the root. 365 * 366 * This subsection returns a locked, refd 'ncp' unless it errors out. 367 * The namecache topology is not allowed to be disconnected, so 368 * encountering a NULL parent will generate EINVAL. This typically 369 * occurs when a directory is removed out from under a process. 370 * 371 * If NLC_DELETE is set neither '.' or '..' can be the last component 372 * of a path. 373 */ 374 if (nlc.nlc_namelen == 1 && nlc.nlc_nameptr[0] == '.') { 375 ncp = cache_get(nd->nl_ncp); 376 wasdotordotdot = 1; 377 } else if (nlc.nlc_namelen == 2 && 378 nlc.nlc_nameptr[0] == '.' && nlc.nlc_nameptr[1] == '.') { 379 ncp = nd->nl_ncp; 380 if (ncp == nd->nl_rootncp) { 381 ncp = cache_get(ncp); 382 } else { 383 while ((ncp->nc_flag & NCF_MOUNTPT) && ncp != nd->nl_rootncp) { 384 if (ncp->nc_parent->nc_flag & NCF_DESTROYED) 385 break; 386 ncp = ncp->nc_parent; /* get to underlying node */ 387 KKASSERT(ncp != NULL && 1); 388 } 389 if (ncp != nd->nl_rootncp) { 390 if (ncp->nc_parent->nc_flag & NCF_DESTROYED) { 391 error = EINVAL; 392 break; 393 } 394 ncp = ncp->nc_parent; 395 if (ncp == NULL) { 396 error = EINVAL; 397 break; 398 } 399 } 400 ncp = cache_get(ncp); 401 } 402 wasdotordotdot = 1; 403 } else { 404 ncp = cache_nlookup(nd->nl_ncp, &nlc); 405 while ((error = cache_resolve(ncp, nd->nl_cred)) == EAGAIN) { 406 printf("[diagnostic] nlookup: relookup %*.*s\n", 407 ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); 408 cache_put(ncp); 409 ncp = cache_nlookup(nd->nl_ncp, &nlc); 410 } 411 wasdotordotdot = 0; 412 } 413 /* 414 * [end of subsection] ncp is locked and ref'd. nd->nl_ncp is ref'd 415 */ 416 417 /* 418 * Resolve the namespace if necessary. The ncp returned by 419 * cache_nlookup() is referenced and locked. 420 * 421 * XXX neither '.' nor '..' should return EAGAIN since they were 422 * previously resolved and thus cannot be newly created ncp's. 423 */ 424 if (ncp->nc_flag & NCF_UNRESOLVED) { 425 error = cache_resolve(ncp, nd->nl_cred); 426 KKASSERT(error != EAGAIN); 427 } else { 428 error = ncp->nc_error; 429 } 430 431 /* 432 * Early completion. ENOENT is not an error if this is the last 433 * component and NLC_CREATE was requested. Note that ncp->nc_error 434 * is left as ENOENT in that case, which we check later on. 435 * 436 * Also handle invalid '.' or '..' components terminating a path 437 * during removal. The standard requires this and pax pretty 438 *stupidly depends on it. 439 */ 440 for (xptr = ptr; *xptr == '/'; ++xptr) 441 ; 442 if (*xptr == 0) { 443 if (error == ENOENT && (nd->nl_flags & NLC_CREATE)) 444 error = naccess(ncp, VCREATE, nd->nl_cred); 445 if (error == 0 && wasdotordotdot && (nd->nl_flags & NLC_DELETE)) 446 error = EINVAL; 447 } 448 449 /* 450 * Early completion on error. 451 */ 452 if (error) { 453 cache_put(ncp); 454 break; 455 } 456 457 /* 458 * If the element is a symlink and it is either not the last 459 * element or it is the last element and we are allowed to 460 * follow symlinks, resolve the symlink. 461 */ 462 if ((ncp->nc_flag & NCF_ISSYMLINK) && 463 (*ptr || (nd->nl_flags & NLC_FOLLOW)) 464 ) { 465 if (nd->nl_loopcnt++ >= MAXSYMLINKS) { 466 error = ELOOP; 467 cache_put(ncp); 468 break; 469 } 470 error = nreadsymlink(nd, ncp, &nlc); 471 cache_put(ncp); 472 if (error) 473 break; 474 475 /* 476 * Concatenate trailing path elements onto the returned symlink. 477 * Note that if the path component (ptr) is not exhausted, it 478 * will being with a '/', so we do not have to add another one. 479 * 480 * The symlink may not be empty. 481 */ 482 len = strlen(ptr); 483 if (nlc.nlc_namelen == 0 || nlc.nlc_namelen + len >= MAXPATHLEN) { 484 error = nlc.nlc_namelen ? ENAMETOOLONG : ENOENT; 485 zfree(namei_zone, nlc.nlc_nameptr); 486 break; 487 } 488 bcopy(ptr, nlc.nlc_nameptr + nlc.nlc_namelen, len + 1); 489 if (nd->nl_flags & NLC_HASBUF) 490 zfree(namei_zone, nd->nl_path); 491 nd->nl_path = nlc.nlc_nameptr; 492 nd->nl_flags |= NLC_HASBUF; 493 ptr = nd->nl_path; 494 495 /* 496 * Go back up to the top to resolve any initial '/'s in the 497 * symlink. 498 */ 499 continue; 500 } 501 502 /* 503 * If the element is a directory and we are crossing a mount point, 504 * retrieve the root of the mounted filesystem from mnt_ncp and 505 * resolve it if necessary. 506 * 507 * XXX mnt_ncp should really be resolved in the mount code. 508 * NOTE! the normal nresolve() code cannot resolve mount point ncp's! 509 * 510 * XXX NOCROSSMOUNT 511 */ 512 while ((ncp->nc_flag & NCF_ISDIR) && ncp->nc_vp->v_mountedhere && 513 (nd->nl_flags & NLC_NOCROSSMOUNT) == 0 514 ) { 515 struct mount *mp; 516 struct vnode *tdp; 517 518 mp = ncp->nc_vp->v_mountedhere; 519 cache_put(ncp); 520 ncp = cache_get(mp->mnt_ncp); 521 522 if (ncp->nc_flag & NCF_UNRESOLVED) { 523 while (vfs_busy(mp, 0, nd->nl_td)) 524 ; 525 error = VFS_ROOT(mp, &tdp); 526 vfs_unbusy(mp, nd->nl_td); 527 if (error) 528 break; 529 cache_setvp(ncp, tdp); 530 vput(tdp); 531 } 532 } 533 if (error) { 534 cache_put(ncp); 535 break; 536 } 537 538 /* 539 * Skip any slashes to get to the next element. If there 540 * are any slashes at all the current element must be a 541 * directory or, in the create case, intended to become a directory. 542 * If it isn't we break without incrementing ptr and fall through 543 * to the failure case below. 544 */ 545 while (*ptr == '/') { 546 if ((ncp->nc_flag & NCF_ISDIR) == 0 && 547 !(nd->nl_flags & NLC_WILLBEDIR) 548 ) { 549 break; 550 } 551 ++ptr; 552 } 553 554 /* 555 * Continuation case: additional elements and the current 556 * element is a directory. 557 */ 558 if (*ptr && (ncp->nc_flag & NCF_ISDIR)) { 559 cache_drop(nd->nl_ncp); 560 cache_unlock(ncp); 561 nd->nl_ncp = ncp; 562 continue; 563 } 564 565 /* 566 * Failure case: additional elements and the current element 567 * is not a directory 568 */ 569 if (*ptr) { 570 cache_put(ncp); 571 error = ENOTDIR; 572 break; 573 } 574 575 /* 576 * Successful lookup of last element. 577 * 578 * Check directory permissions if a deletion is specified. 579 */ 580 if (*ptr == 0 && (nd->nl_flags & NLC_DELETE)) { 581 if ((error = naccess(ncp, VDELETE, nd->nl_cred)) != 0) { 582 cache_put(ncp); 583 break; 584 } 585 } 586 587 /* 588 * XXX vnode canvmio (test in mmap(), read(), and write()) 589 */ 590 591 /* 592 * Termination: no more elements. If NLC_CREATE was set the 593 * ncp may represent a negative hit (ncp->nc_error will be ENOENT), 594 * but we still return an error code of 0. 595 */ 596 cache_drop(nd->nl_ncp); 597 nd->nl_ncp = ncp; 598 nd->nl_flags |= NLC_NCPISLOCKED; 599 error = 0; 600 break; 601 } 602 return(error); 603 } 604 605 /* 606 * Resolve a mount point's glue ncp. This ncp connects creates the illusion 607 * of continuity in the namecache tree by connecting the ncp related to the 608 * vnode under the mount to the ncp related to the mount's root vnode. 609 * 610 * If no error occured a locked, ref'd ncp is stored in *ncpp. 611 */ 612 int 613 nlookup_mp(struct mount *mp, struct namecache **ncpp) 614 { 615 struct namecache *ncp; 616 struct vnode *vp; 617 int error; 618 619 error = 0; 620 ncp = mp->mnt_ncp; 621 cache_get(ncp); 622 if (ncp->nc_flag & NCF_UNRESOLVED) { 623 while (vfs_busy(mp, 0, curthread)) 624 ; 625 error = VFS_ROOT(mp, &vp); 626 vfs_unbusy(mp, curthread); 627 if (error) { 628 cache_put(ncp); 629 ncp = NULL; 630 } else { 631 cache_setvp(ncp, vp); 632 vput(vp); 633 } 634 } 635 *ncpp = ncp; 636 return(error); 637 } 638 639 /* 640 * Read the contents of a symlink, allocate a path buffer out of the 641 * namei_zone and initialize the supplied nlcomponent with the result. 642 * 643 * If an error occurs no buffer will be allocated or returned in the nlc. 644 */ 645 int 646 nreadsymlink(struct nlookupdata *nd, struct namecache *ncp, 647 struct nlcomponent *nlc) 648 { 649 struct vnode *vp; 650 struct iovec aiov; 651 struct uio auio; 652 int linklen; 653 int error; 654 char *cp; 655 656 nlc->nlc_nameptr = NULL; 657 nlc->nlc_namelen = 0; 658 if (ncp->nc_vp == NULL) 659 return(ENOENT); 660 if ((error = cache_vget(ncp, nd->nl_cred, LK_SHARED, &vp)) != 0) 661 return(error); 662 cp = zalloc(namei_zone); 663 aiov.iov_base = cp; 664 aiov.iov_len = MAXPATHLEN; 665 auio.uio_iov = &aiov; 666 auio.uio_iovcnt = 1; 667 auio.uio_offset = 0; 668 auio.uio_rw = UIO_READ; 669 auio.uio_segflg = UIO_SYSSPACE; 670 auio.uio_td = nd->nl_td; 671 auio.uio_resid = MAXPATHLEN - 1; 672 error = VOP_READLINK(vp, &auio, nd->nl_cred); 673 if (error) 674 goto fail; 675 linklen = MAXPATHLEN - 1 - auio.uio_resid; 676 if (varsym_enable) { 677 linklen = varsymreplace(cp, linklen, MAXPATHLEN - 1); 678 if (linklen < 0) { 679 error = ENAMETOOLONG; 680 goto fail; 681 } 682 } 683 cp[linklen] = 0; 684 nlc->nlc_nameptr = cp; 685 nlc->nlc_namelen = linklen; 686 vput(vp); 687 return(0); 688 fail: 689 zfree(namei_zone, cp); 690 vput(vp); 691 return(error); 692 } 693 694 /* 695 * Check access [XXX cache vattr!] [XXX quota] 696 * 697 * Generally check the V* access bits from sys/vnode.h. All specified bits 698 * must pass for this function to return 0. 699 * 700 * If VCREATE is specified and the target ncp represents a non-existant 701 * file or dir, or if VDELETE is specified and the target exists, the parent 702 * directory is checked for VWRITE. If VEXCL is specified and the target 703 * ncp represents a positive hit, an error is returned. 704 * 705 * If VCREATE is not specified and the target does not exist (negative hit), 706 * ENOENT is returned. Note that nlookup() does not (and should not) return 707 * ENOENT for non-existant leafs. 708 * 709 * The passed ncp may or may not be locked. The caller should use a 710 * locked ncp on leaf lookups, especially for VCREATE, VDELETE, and VEXCL 711 * checks. 712 */ 713 int 714 naccess(struct namecache *ncp, int vmode, struct ucred *cred) 715 { 716 struct namecache *par; 717 struct vnode *vp; 718 struct vattr va; 719 int error; 720 721 if (ncp->nc_flag & NCF_UNRESOLVED) { 722 cache_lock(ncp); 723 cache_resolve(ncp, cred); 724 cache_unlock(ncp); 725 } 726 error = ncp->nc_error; 727 if (vmode & (VDELETE|VCREATE|VEXCL)) { 728 if (((vmode & VCREATE) && ncp->nc_vp == NULL) || 729 ((vmode & VDELETE) && ncp->nc_vp != NULL) 730 ) { 731 if ((par = ncp->nc_parent) == NULL) { 732 if (error != EAGAIN) 733 error = EINVAL; 734 } else { 735 cache_hold(par); 736 error = naccess(par, VWRITE, cred); 737 cache_drop(par); 738 } 739 } 740 if ((vmode & VEXCL) && ncp->nc_vp != NULL) 741 error = EEXIST; 742 } 743 if (error == 0) { 744 error = cache_vget(ncp, cred, LK_SHARED, &vp); 745 if (error == ENOENT) { 746 if (vmode & VCREATE) 747 error = 0; 748 } else if (error == 0) { 749 /* XXX cache the va in the namecache or in the vnode */ 750 if ((error = VOP_GETATTR(vp, &va, curthread)) == 0) { 751 if ((vmode & VWRITE) && vp->v_mount) { 752 if (vp->v_mount->mnt_flag & MNT_RDONLY) 753 error = EROFS; 754 } 755 } 756 vput(vp); 757 if (error == 0) 758 error = naccess_va(&va, vmode, cred); 759 } 760 } 761 return(error); 762 } 763 764 /* 765 * Check the requested access against the given vattr using cred. 766 */ 767 int 768 naccess_va(struct vattr *va, int vmode, struct ucred *cred) 769 { 770 int i; 771 772 /* 773 * Test the immutable bit for files, directories, and softlinks. 774 */ 775 if (vmode & (VWRITE|VDELETE)) { 776 if (va->va_type == VDIR || va->va_type == VLNK || va->va_type == VREG) { 777 if (va->va_flags & IMMUTABLE) 778 return (EPERM); 779 } 780 } 781 782 /* 783 * root gets universal access 784 */ 785 if (cred->cr_uid == 0) 786 return(0); 787 788 /* 789 * Check owner perms, group perms, and world perms 790 */ 791 vmode &= S_IRWXU; 792 if (cred->cr_uid == va->va_uid) { 793 if ((vmode & va->va_mode) != vmode) 794 return(EACCES); 795 return(0); 796 } 797 798 vmode >>= 3; 799 for (i = 0; i < cred->cr_ngroups; ++i) { 800 if (va->va_gid == cred->cr_groups[i]) { 801 if ((vmode & va->va_mode) != vmode) 802 return(EACCES); 803 return(0); 804 } 805 } 806 807 vmode >>= 3; 808 if ((vmode & va->va_mode) != vmode) 809 return(EACCES); 810 return(0); 811 } 812 813