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.17 2006/06/01 06:10:50 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 <sys/objcache.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 = objcache_get(namei_oc, M_WAITOK); 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 = objcache_get(namei_oc, M_WAITOK); 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 objcache_put(namei_oc, 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); 228 nd->nl_flags &= ~NLC_LOCKVP; 229 } 230 vn_close(nd->nl_open_vp, nd->nl_vp_fmode); 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, 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 objcache_put(namei_oc, 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 objcache_put(namei_oc, 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)) 524 ; 525 error = VFS_ROOT(mp, &tdp); 526 vfs_unbusy(mp); 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 * Termination: no more elements. If NLC_CREATE was set the 589 * ncp may represent a negative hit (ncp->nc_error will be ENOENT), 590 * but we still return an error code of 0. 591 */ 592 cache_drop(nd->nl_ncp); 593 nd->nl_ncp = ncp; 594 nd->nl_flags |= NLC_NCPISLOCKED; 595 error = 0; 596 break; 597 } 598 return(error); 599 } 600 601 /* 602 * Resolve a mount point's glue ncp. This ncp connects creates the illusion 603 * of continuity in the namecache tree by connecting the ncp related to the 604 * vnode under the mount to the ncp related to the mount's root vnode. 605 * 606 * If no error occured a locked, ref'd ncp is stored in *ncpp. 607 */ 608 int 609 nlookup_mp(struct mount *mp, struct namecache **ncpp) 610 { 611 struct namecache *ncp; 612 struct vnode *vp; 613 int error; 614 615 error = 0; 616 ncp = mp->mnt_ncp; 617 cache_get(ncp); 618 if (ncp->nc_flag & NCF_UNRESOLVED) { 619 while (vfs_busy(mp, 0)) 620 ; 621 error = VFS_ROOT(mp, &vp); 622 vfs_unbusy(mp); 623 if (error) { 624 cache_put(ncp); 625 ncp = NULL; 626 } else { 627 cache_setvp(ncp, vp); 628 vput(vp); 629 } 630 } 631 *ncpp = ncp; 632 return(error); 633 } 634 635 /* 636 * Read the contents of a symlink, allocate a path buffer out of the 637 * namei_oc and initialize the supplied nlcomponent with the result. 638 * 639 * If an error occurs no buffer will be allocated or returned in the nlc. 640 */ 641 int 642 nreadsymlink(struct nlookupdata *nd, struct namecache *ncp, 643 struct nlcomponent *nlc) 644 { 645 struct vnode *vp; 646 struct iovec aiov; 647 struct uio auio; 648 int linklen; 649 int error; 650 char *cp; 651 652 nlc->nlc_nameptr = NULL; 653 nlc->nlc_namelen = 0; 654 if (ncp->nc_vp == NULL) 655 return(ENOENT); 656 if ((error = cache_vget(ncp, nd->nl_cred, LK_SHARED, &vp)) != 0) 657 return(error); 658 cp = objcache_get(namei_oc, M_WAITOK); 659 aiov.iov_base = cp; 660 aiov.iov_len = MAXPATHLEN; 661 auio.uio_iov = &aiov; 662 auio.uio_iovcnt = 1; 663 auio.uio_offset = 0; 664 auio.uio_rw = UIO_READ; 665 auio.uio_segflg = UIO_SYSSPACE; 666 auio.uio_td = nd->nl_td; 667 auio.uio_resid = MAXPATHLEN - 1; 668 error = VOP_READLINK(vp, &auio, nd->nl_cred); 669 if (error) 670 goto fail; 671 linklen = MAXPATHLEN - 1 - auio.uio_resid; 672 if (varsym_enable) { 673 linklen = varsymreplace(cp, linklen, MAXPATHLEN - 1); 674 if (linklen < 0) { 675 error = ENAMETOOLONG; 676 goto fail; 677 } 678 } 679 cp[linklen] = 0; 680 nlc->nlc_nameptr = cp; 681 nlc->nlc_namelen = linklen; 682 vput(vp); 683 return(0); 684 fail: 685 objcache_put(namei_oc, cp); 686 vput(vp); 687 return(error); 688 } 689 690 /* 691 * Check access [XXX cache vattr!] [XXX quota] 692 * 693 * Generally check the V* access bits from sys/vnode.h. All specified bits 694 * must pass for this function to return 0. 695 * 696 * If VCREATE is specified and the target ncp represents a non-existant 697 * file or dir, or if VDELETE is specified and the target exists, the parent 698 * directory is checked for VWRITE. If VEXCL is specified and the target 699 * ncp represents a positive hit, an error is returned. 700 * 701 * If VCREATE is not specified and the target does not exist (negative hit), 702 * ENOENT is returned. Note that nlookup() does not (and should not) return 703 * ENOENT for non-existant leafs. 704 * 705 * The passed ncp may or may not be locked. The caller should use a 706 * locked ncp on leaf lookups, especially for VCREATE, VDELETE, and VEXCL 707 * checks. 708 */ 709 int 710 naccess(struct namecache *ncp, int vmode, struct ucred *cred) 711 { 712 struct namecache *par; 713 struct vnode *vp; 714 struct vattr va; 715 int error; 716 717 if (ncp->nc_flag & NCF_UNRESOLVED) { 718 cache_lock(ncp); 719 cache_resolve(ncp, cred); 720 cache_unlock(ncp); 721 } 722 error = ncp->nc_error; 723 if (vmode & (VDELETE|VCREATE|VEXCL)) { 724 if (((vmode & VCREATE) && ncp->nc_vp == NULL) || 725 ((vmode & VDELETE) && ncp->nc_vp != NULL) 726 ) { 727 if ((par = ncp->nc_parent) == NULL) { 728 if (error != EAGAIN) 729 error = EINVAL; 730 } else { 731 cache_hold(par); 732 error = naccess(par, VWRITE, cred); 733 cache_drop(par); 734 } 735 } 736 if ((vmode & VEXCL) && ncp->nc_vp != NULL) 737 error = EEXIST; 738 } 739 if (error == 0) { 740 error = cache_vget(ncp, cred, LK_SHARED, &vp); 741 if (error == ENOENT) { 742 if (vmode & VCREATE) 743 error = 0; 744 } else if (error == 0) { 745 /* XXX cache the va in the namecache or in the vnode */ 746 if ((error = VOP_GETATTR(vp, &va)) == 0) { 747 if ((vmode & VWRITE) && vp->v_mount) { 748 if (vp->v_mount->mnt_flag & MNT_RDONLY) 749 error = EROFS; 750 } 751 } 752 vput(vp); 753 if (error == 0) 754 error = naccess_va(&va, vmode, cred); 755 } 756 } 757 return(error); 758 } 759 760 /* 761 * Check the requested access against the given vattr using cred. 762 */ 763 int 764 naccess_va(struct vattr *va, int vmode, struct ucred *cred) 765 { 766 int i; 767 768 /* 769 * Test the immutable bit for files, directories, and softlinks. 770 */ 771 if (vmode & (VWRITE|VDELETE)) { 772 if (va->va_type == VDIR || va->va_type == VLNK || va->va_type == VREG) { 773 if (va->va_flags & IMMUTABLE) 774 return (EPERM); 775 } 776 } 777 778 /* 779 * root gets universal access 780 */ 781 if (cred->cr_uid == 0) 782 return(0); 783 784 /* 785 * Check owner perms, group perms, and world perms 786 */ 787 vmode &= S_IRWXU; 788 if (cred->cr_uid == va->va_uid) { 789 if ((vmode & va->va_mode) != vmode) 790 return(EACCES); 791 return(0); 792 } 793 794 vmode >>= 3; 795 for (i = 0; i < cred->cr_ngroups; ++i) { 796 if (va->va_gid == cred->cr_groups[i]) { 797 if ((vmode & va->va_mode) != vmode) 798 return(EACCES); 799 return(0); 800 } 801 } 802 803 vmode >>= 3; 804 if ((vmode & va->va_mode) != vmode) 805 return(EACCES); 806 return(0); 807 } 808 809