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.25 2008/07/19 04:43:33 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 cache_copy(&p->p_fd->fd_ncdir, &nd->nl_nch); 113 cache_copy(&p->p_fd->fd_nrdir, &nd->nl_rootnch); 114 if (p->p_fd->fd_njdir.ncp) 115 cache_copy(&p->p_fd->fd_njdir, &nd->nl_jailnch); 116 nd->nl_cred = crhold(p->p_ucred); 117 } else { 118 cache_copy(&rootnch, &nd->nl_nch); 119 cache_copy(&nd->nl_nch, &nd->nl_rootnch); 120 cache_copy(&nd->nl_nch, &nd->nl_jailnch); 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. rootnch 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 nchandle *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 cache_copy(ncstart, &nd->nl_nch); 164 cache_copy(&rootnch, &nd->nl_rootnch); 165 cache_copy(&rootnch, &nd->nl_jailnch); 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_nch.ncp) { 202 if (nd->nl_flags & NLC_NCPISLOCKED) { 203 nd->nl_flags &= ~NLC_NCPISLOCKED; 204 cache_unlock(&nd->nl_nch); 205 } 206 cache_drop(&nd->nl_nch); 207 } 208 if (nd->nl_rootnch.ncp) 209 cache_drop(&nd->nl_rootnch); 210 if (nd->nl_jailnch.ncp) 211 cache_drop(&nd->nl_jailnch); 212 if ((nd->nl_flags & NLC_HASBUF) && nd->nl_path) { 213 objcache_put(namei_oc, nd->nl_path); 214 nd->nl_path = NULL; 215 } 216 if (nd->nl_cred) { 217 crfree(nd->nl_cred); 218 nd->nl_cred = NULL; 219 } 220 if (nd->nl_open_vp) { 221 if (nd->nl_flags & NLC_LOCKVP) { 222 vn_unlock(nd->nl_open_vp); 223 nd->nl_flags &= ~NLC_LOCKVP; 224 } 225 vn_close(nd->nl_open_vp, nd->nl_vp_fmode); 226 nd->nl_open_vp = NULL; 227 } 228 if (nd->nl_dvp) { 229 vrele(nd->nl_dvp); 230 nd->nl_dvp = NULL; 231 } 232 nd->nl_flags = 0; /* clear remaining flags (just clear everything) */ 233 } 234 235 void 236 nlookup_zero(struct nlookupdata *nd) 237 { 238 bzero(nd, sizeof(struct nlookupdata)); 239 } 240 241 /* 242 * Simple all-in-one nlookup. Returns a locked namecache structure or NULL 243 * if an error occured. 244 * 245 * Note that the returned ncp is not checked for permissions, though VEXEC 246 * is checked on the directory path leading up to the result. The caller 247 * must call naccess() to check the permissions of the returned leaf. 248 */ 249 struct nchandle 250 nlookup_simple(const char *str, enum uio_seg seg, 251 int niflags, int *error) 252 { 253 struct nlookupdata nd; 254 struct nchandle nch; 255 256 *error = nlookup_init(&nd, str, seg, niflags); 257 if (*error == 0) { 258 if ((*error = nlookup(&nd)) == 0) { 259 nch = nd.nl_nch; /* keep hold ref from structure */ 260 cache_zero(&nd.nl_nch); /* and NULL out */ 261 } else { 262 cache_zero(&nch); 263 } 264 nlookup_done(&nd); 265 } else { 266 cache_zero(&nch); 267 } 268 return(nch); 269 } 270 271 /* 272 * Do a generic nlookup. Note that the passed nd is not nlookup_done()'d 273 * on return, even if an error occurs. If no error occurs the returned 274 * nl_nch is always referenced and locked, otherwise it may or may not be. 275 * 276 * Intermediate directory elements, including the current directory, require 277 * execute (search) permission. nlookup does not examine the access 278 * permissions on the returned element. 279 * 280 * If NLC_CREATE or NLC_DELETE is set the last directory must allow node 281 * creation (VCREATE/VDELETE), and an error code of 0 will be returned for 282 * a non-existant target. Otherwise a non-existant target will cause 283 * ENOENT to be returned. 284 * 285 * If NLC_REFDVP is set nd->nl_dvp will be set to the directory vnode 286 * of the returned entry. The vnode will be referenced, but not locked, 287 * and will be released by nlookup_done() along with everything else. 288 */ 289 int 290 nlookup(struct nlookupdata *nd) 291 { 292 struct nlcomponent nlc; 293 struct nchandle nch; 294 struct mount *mp; 295 int wasdotordotdot; 296 char *ptr; 297 char *xptr; 298 int error; 299 int len; 300 301 #ifdef KTRACE 302 if (KTRPOINT(nd->nl_td, KTR_NAMEI)) 303 ktrnamei(nd->nl_td->td_lwp, nd->nl_path); 304 #endif 305 bzero(&nlc, sizeof(nlc)); 306 307 /* 308 * Setup for the loop. The current working namecache element must 309 * be in a refd + unlocked state. This typically the case on entry except 310 * when stringing nlookup()'s along in a chain, since nlookup() always 311 * returns nl_nch in a locked state. 312 */ 313 nd->nl_loopcnt = 0; 314 if (nd->nl_flags & NLC_NCPISLOCKED) { 315 nd->nl_flags &= ~NLC_NCPISLOCKED; 316 cache_unlock(&nd->nl_nch); 317 } 318 if (nd->nl_dvp ) { 319 vrele(nd->nl_dvp); 320 nd->nl_dvp = NULL; 321 } 322 ptr = nd->nl_path; 323 324 /* 325 * Loop on the path components. At the top of the loop nd->nl_nch 326 * is ref'd and unlocked and represents our current position. 327 */ 328 for (;;) { 329 /* 330 * Check if the root directory should replace the current 331 * directory. This is done at the start of a translation 332 * or after a symbolic link has been found. In other cases 333 * ptr will never be pointing at a '/'. 334 */ 335 if (*ptr == '/') { 336 do { 337 ++ptr; 338 } while (*ptr == '/'); 339 cache_copy(&nd->nl_rootnch, &nch); 340 cache_drop(&nd->nl_nch); 341 nd->nl_nch = nch; 342 343 /* 344 * Fast-track termination. There is no parent directory of 345 * the root in the same mount from the point of view of 346 * the caller so return EPERM if NLC_REFDVP is specified. 347 * e.g. 'rmdir /' is not allowed. 348 */ 349 if (*ptr == 0) { 350 if (nd->nl_flags & NLC_REFDVP) { 351 error = EPERM; 352 } else { 353 cache_lock(&nd->nl_nch); 354 nd->nl_flags |= NLC_NCPISLOCKED; 355 error = 0; 356 } 357 break; 358 } 359 continue; 360 } 361 362 /* 363 * Check directory search permissions. 364 */ 365 if ((error = naccess(&nd->nl_nch, VEXEC, nd->nl_cred)) != 0) 366 break; 367 368 /* 369 * Extract the path component 370 */ 371 nlc.nlc_nameptr = ptr; 372 while (*ptr && *ptr != '/') 373 ++ptr; 374 nlc.nlc_namelen = ptr - nlc.nlc_nameptr; 375 376 /* 377 * Lookup the path component in the cache, creating an unresolved 378 * entry if necessary. We have to handle "." and ".." as special 379 * cases. 380 * 381 * When handling ".." we have to detect a traversal back through a 382 * mount point. If we are at the root, ".." just returns the root. 383 * 384 * This subsection returns a locked, refd 'nch' unless it errors out. 385 * The namecache topology is not allowed to be disconnected, so 386 * encountering a NULL parent will generate EINVAL. This typically 387 * occurs when a directory is removed out from under a process. 388 * 389 * If NLC_DELETE is set neither '.' or '..' can be the last component 390 * of a path. 391 */ 392 if (nlc.nlc_namelen == 1 && nlc.nlc_nameptr[0] == '.') { 393 cache_get(&nd->nl_nch, &nch); 394 wasdotordotdot = 1; 395 } else if (nlc.nlc_namelen == 2 && 396 nlc.nlc_nameptr[0] == '.' && nlc.nlc_nameptr[1] == '.') { 397 if (nd->nl_nch.mount == nd->nl_rootnch.mount && 398 nd->nl_nch.ncp == nd->nl_rootnch.ncp 399 ) { 400 /* 401 * ".." at the root returns the root 402 */ 403 cache_get(&nd->nl_nch, &nch); 404 } else { 405 /* 406 * Locate the parent ncp. If we are at the root of a 407 * filesystem mount we have to skip to the mounted-on 408 * point in the underlying filesystem. 409 */ 410 nch = nd->nl_nch; 411 while (nch.ncp == nch.mount->mnt_ncmountpt.ncp) 412 nch = nch.mount->mnt_ncmounton; 413 nch.ncp = nch.ncp->nc_parent; 414 KKASSERT(nch.ncp != NULL); 415 cache_get(&nch, &nch); 416 } 417 wasdotordotdot = 1; 418 } else { 419 nch = cache_nlookup(&nd->nl_nch, &nlc); 420 while ((error = cache_resolve(&nch, nd->nl_cred)) == EAGAIN) { 421 kprintf("[diagnostic] nlookup: relookup %*.*s\n", 422 nch.ncp->nc_nlen, nch.ncp->nc_nlen, nch.ncp->nc_name); 423 cache_put(&nch); 424 nch = cache_nlookup(&nd->nl_nch, &nlc); 425 } 426 wasdotordotdot = 0; 427 } 428 /* 429 * [end of subsection] ncp is locked and ref'd. nd->nl_nch is ref'd 430 */ 431 432 /* 433 * Resolve the namespace if necessary. The ncp returned by 434 * cache_nlookup() is referenced and locked. 435 * 436 * XXX neither '.' nor '..' should return EAGAIN since they were 437 * previously resolved and thus cannot be newly created ncp's. 438 */ 439 if (nch.ncp->nc_flag & NCF_UNRESOLVED) { 440 error = cache_resolve(&nch, nd->nl_cred); 441 KKASSERT(error != EAGAIN); 442 } else { 443 error = nch.ncp->nc_error; 444 } 445 446 /* 447 * Early completion. ENOENT is not an error if this is the last 448 * component and NLC_CREATE was requested. Note that ncp->nc_error 449 * is left as ENOENT in that case, which we check later on. 450 * 451 * Also handle invalid '.' or '..' components terminating a path 452 * during removal. The standard requires this and pax pretty 453 * stupidly depends on it. 454 */ 455 for (xptr = ptr; *xptr == '/'; ++xptr) 456 ; 457 if (*xptr == 0) { 458 if (error == ENOENT && (nd->nl_flags & NLC_CREATE)) { 459 if (nd->nl_flags & NLC_NFS_RDONLY) 460 error = EROFS; 461 else 462 error = naccess(&nch, VCREATE, nd->nl_cred); 463 } 464 if (error == 0 && wasdotordotdot && (nd->nl_flags & NLC_DELETE)) 465 error = EINVAL; 466 } 467 468 /* 469 * Early completion on error. 470 */ 471 if (error) { 472 cache_put(&nch); 473 break; 474 } 475 476 /* 477 * If the element is a symlink and it is either not the last 478 * element or it is the last element and we are allowed to 479 * follow symlinks, resolve the symlink. 480 */ 481 if ((nch.ncp->nc_flag & NCF_ISSYMLINK) && 482 (*ptr || (nd->nl_flags & NLC_FOLLOW)) 483 ) { 484 if (nd->nl_loopcnt++ >= MAXSYMLINKS) { 485 error = ELOOP; 486 cache_put(&nch); 487 break; 488 } 489 error = nreadsymlink(nd, &nch, &nlc); 490 cache_put(&nch); 491 if (error) 492 break; 493 494 /* 495 * Concatenate trailing path elements onto the returned symlink. 496 * Note that if the path component (ptr) is not exhausted, it 497 * will being with a '/', so we do not have to add another one. 498 * 499 * The symlink may not be empty. 500 */ 501 len = strlen(ptr); 502 if (nlc.nlc_namelen == 0 || nlc.nlc_namelen + len >= MAXPATHLEN) { 503 error = nlc.nlc_namelen ? ENAMETOOLONG : ENOENT; 504 objcache_put(namei_oc, nlc.nlc_nameptr); 505 break; 506 } 507 bcopy(ptr, nlc.nlc_nameptr + nlc.nlc_namelen, len + 1); 508 if (nd->nl_flags & NLC_HASBUF) 509 objcache_put(namei_oc, nd->nl_path); 510 nd->nl_path = nlc.nlc_nameptr; 511 nd->nl_flags |= NLC_HASBUF; 512 ptr = nd->nl_path; 513 514 /* 515 * Go back up to the top to resolve any initial '/'s in the 516 * symlink. 517 */ 518 continue; 519 } 520 521 /* 522 * If the element is a directory and we are crossing a mount point, 523 * Locate the mount. 524 */ 525 while ((nch.ncp->nc_flag & NCF_ISMOUNTPT) && 526 (nd->nl_flags & NLC_NOCROSSMOUNT) == 0 && 527 (mp = cache_findmount(&nch)) != NULL 528 ) { 529 struct vnode *tdp; 530 531 cache_put(&nch); 532 cache_get(&mp->mnt_ncmountpt, &nch); 533 534 if (nch.ncp->nc_flag & NCF_UNRESOLVED) { 535 while (vfs_busy(mp, 0)) 536 ; 537 error = VFS_ROOT(mp, &tdp); 538 vfs_unbusy(mp); 539 if (error) 540 break; 541 cache_setvp(&nch, tdp); 542 vput(tdp); 543 } 544 } 545 if (error) { 546 cache_put(&nch); 547 break; 548 } 549 550 /* 551 * Skip any slashes to get to the next element. If there 552 * are any slashes at all the current element must be a 553 * directory or, in the create case, intended to become a directory. 554 * If it isn't we break without incrementing ptr and fall through 555 * to the failure case below. 556 */ 557 while (*ptr == '/') { 558 if ((nch.ncp->nc_flag & NCF_ISDIR) == 0 && 559 !(nd->nl_flags & NLC_WILLBEDIR) 560 ) { 561 break; 562 } 563 ++ptr; 564 } 565 566 /* 567 * Continuation case: additional elements and the current 568 * element is a directory. 569 */ 570 if (*ptr && (nch.ncp->nc_flag & NCF_ISDIR)) { 571 cache_drop(&nd->nl_nch); 572 cache_unlock(&nch); 573 nd->nl_nch = nch; 574 continue; 575 } 576 577 /* 578 * Failure case: additional elements and the current element 579 * is not a directory 580 */ 581 if (*ptr) { 582 cache_put(&nch); 583 error = ENOTDIR; 584 break; 585 } 586 587 /* 588 * Successful lookup of last element. 589 * 590 * Check directory permissions if a deletion is specified. 591 */ 592 if (*ptr == 0 && (nd->nl_flags & NLC_DELETE)) { 593 if ((error = naccess(&nch, VDELETE, nd->nl_cred)) != 0) { 594 cache_put(&nch); 595 break; 596 } 597 } 598 599 /* 600 * Termination: no more elements. If NLC_CREATE was set the 601 * ncp may represent a negative hit (ncp->nc_error will be ENOENT), 602 * but we still return an error code of 0. 603 * 604 * If NLC_REFDVP is set acquire a referenced parent dvp. 605 */ 606 if (nd->nl_flags & NLC_REFDVP) { 607 error = cache_vref(&nd->nl_nch, nd->nl_cred, &nd->nl_dvp); 608 if (error) { 609 kprintf("NLC_REFDVP: Cannot ref dvp of %p\n", nch.ncp); 610 cache_put(&nch); 611 break; 612 } 613 } 614 cache_drop(&nd->nl_nch); 615 nd->nl_nch = nch; 616 nd->nl_flags |= NLC_NCPISLOCKED; 617 error = 0; 618 break; 619 } 620 return(error); 621 } 622 623 /* 624 * Resolve a mount point's glue ncp. This ncp connects creates the illusion 625 * of continuity in the namecache tree by connecting the ncp related to the 626 * vnode under the mount to the ncp related to the mount's root vnode. 627 * 628 * If no error occured a locked, ref'd ncp is stored in *ncpp. 629 */ 630 int 631 nlookup_mp(struct mount *mp, struct nchandle *nch) 632 { 633 struct vnode *vp; 634 int error; 635 636 error = 0; 637 cache_get(&mp->mnt_ncmountpt, nch); 638 if (nch->ncp->nc_flag & NCF_UNRESOLVED) { 639 while (vfs_busy(mp, 0)) 640 ; 641 error = VFS_ROOT(mp, &vp); 642 vfs_unbusy(mp); 643 if (error) { 644 cache_put(nch); 645 } else { 646 cache_setvp(nch, vp); 647 vput(vp); 648 } 649 } 650 return(error); 651 } 652 653 /* 654 * Read the contents of a symlink, allocate a path buffer out of the 655 * namei_oc and initialize the supplied nlcomponent with the result. 656 * 657 * If an error occurs no buffer will be allocated or returned in the nlc. 658 */ 659 int 660 nreadsymlink(struct nlookupdata *nd, struct nchandle *nch, 661 struct nlcomponent *nlc) 662 { 663 struct vnode *vp; 664 struct iovec aiov; 665 struct uio auio; 666 int linklen; 667 int error; 668 char *cp; 669 670 nlc->nlc_nameptr = NULL; 671 nlc->nlc_namelen = 0; 672 if (nch->ncp->nc_vp == NULL) 673 return(ENOENT); 674 if ((error = cache_vget(nch, nd->nl_cred, LK_SHARED, &vp)) != 0) 675 return(error); 676 cp = objcache_get(namei_oc, M_WAITOK); 677 aiov.iov_base = cp; 678 aiov.iov_len = MAXPATHLEN; 679 auio.uio_iov = &aiov; 680 auio.uio_iovcnt = 1; 681 auio.uio_offset = 0; 682 auio.uio_rw = UIO_READ; 683 auio.uio_segflg = UIO_SYSSPACE; 684 auio.uio_td = nd->nl_td; 685 auio.uio_resid = MAXPATHLEN - 1; 686 error = VOP_READLINK(vp, &auio, nd->nl_cred); 687 if (error) 688 goto fail; 689 linklen = MAXPATHLEN - 1 - auio.uio_resid; 690 if (varsym_enable) { 691 linklen = varsymreplace(cp, linklen, MAXPATHLEN - 1); 692 if (linklen < 0) { 693 error = ENAMETOOLONG; 694 goto fail; 695 } 696 } 697 cp[linklen] = 0; 698 nlc->nlc_nameptr = cp; 699 nlc->nlc_namelen = linklen; 700 vput(vp); 701 return(0); 702 fail: 703 objcache_put(namei_oc, cp); 704 vput(vp); 705 return(error); 706 } 707 708 /* 709 * Check access [XXX cache vattr!] [XXX quota] 710 * 711 * Generally check the V* access bits from sys/vnode.h. All specified bits 712 * must pass for this function to return 0. 713 * 714 * If VCREATE is specified and the target ncp represents a non-existant 715 * file or dir, or if VDELETE is specified and the target exists, the parent 716 * directory is checked for VWRITE. If VEXCL is specified and the target 717 * ncp represents a positive hit, an error is returned. 718 * 719 * If VCREATE is not specified and the target does not exist (negative hit), 720 * ENOENT is returned. Note that nlookup() does not (and should not) return 721 * ENOENT for non-existant leafs. 722 * 723 * The passed ncp may or may not be locked. The caller should use a 724 * locked ncp on leaf lookups, especially for VCREATE, VDELETE, and VEXCL 725 * checks. 726 */ 727 int 728 naccess(struct nchandle *nch, int vmode, struct ucred *cred) 729 { 730 struct nchandle par; 731 struct vnode *vp; 732 struct vattr va; 733 int error; 734 735 if (nch->ncp->nc_flag & NCF_UNRESOLVED) { 736 cache_lock(nch); 737 cache_resolve(nch, cred); 738 cache_unlock(nch); 739 } 740 error = nch->ncp->nc_error; 741 if (vmode & (VDELETE|VCREATE|VEXCL)) { 742 if (((vmode & VCREATE) && nch->ncp->nc_vp == NULL) || 743 ((vmode & VDELETE) && nch->ncp->nc_vp != NULL) 744 ) { 745 if ((par.ncp = nch->ncp->nc_parent) == NULL) { 746 if (error != EAGAIN) 747 error = EINVAL; 748 } else { 749 par.mount = nch->mount; 750 cache_hold(&par); 751 error = naccess(&par, VWRITE, cred); 752 cache_drop(&par); 753 } 754 } 755 if ((vmode & VEXCL) && nch->ncp->nc_vp != NULL) 756 error = EEXIST; 757 } 758 if (error == 0) { 759 error = cache_vget(nch, cred, LK_SHARED, &vp); 760 if (error == ENOENT) { 761 if (vmode & VCREATE) 762 error = 0; 763 } else if (error == 0) { 764 /* XXX cache the va in the namecache or in the vnode */ 765 if ((error = VOP_GETATTR(vp, &va)) == 0) { 766 if ((vmode & VWRITE) && vp->v_mount) { 767 if (vp->v_mount->mnt_flag & MNT_RDONLY) 768 error = EROFS; 769 } 770 } 771 vput(vp); 772 if (error == 0) 773 error = naccess_va(&va, vmode, cred); 774 } 775 } 776 return(error); 777 } 778 779 /* 780 * Check the requested access against the given vattr using cred. 781 */ 782 int 783 naccess_va(struct vattr *va, int vmode, struct ucred *cred) 784 { 785 int i; 786 787 /* 788 * Test the immutable bit for files, directories, and softlinks. 789 */ 790 if (vmode & (VWRITE|VDELETE)) { 791 if (va->va_type == VDIR || va->va_type == VLNK || va->va_type == VREG) { 792 if (va->va_flags & IMMUTABLE) 793 return (EPERM); 794 } 795 } 796 797 /* 798 * root gets universal access 799 */ 800 if (cred->cr_uid == 0) 801 return(0); 802 803 /* 804 * Check owner perms, group perms, and world perms 805 */ 806 vmode &= S_IRWXU; 807 if (cred->cr_uid == va->va_uid) { 808 if ((vmode & va->va_mode) != vmode) 809 return(EACCES); 810 return(0); 811 } 812 813 vmode >>= 3; 814 for (i = 0; i < cred->cr_ngroups; ++i) { 815 if (va->va_gid == cred->cr_groups[i]) { 816 if ((vmode & va->va_mode) != vmode) 817 return(EACCES); 818 return(0); 819 } 820 } 821 822 vmode >>= 3; 823 if ((vmode & va->va_mode) != vmode) 824 return(EACCES); 825 return(0); 826 } 827 828