* resolve_symlink must _always_ be called on an APR_LNK file type! * It will resolve the actual target file type, modification date, etc, * and provide any processing required for symlink evaluation. * Path must already be cleaned, no trailing slash, no multi-slashes, * and don't call this on the root! * * Simply, the number of times we deref a symlink are minimal compared * to the number o
| 531 | * it points at a 'nasty' - we must always rerun check_safe_file (or similar.) |
| 532 | */ |
| 533 | static int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p) |
| 534 | { |
| 535 | apr_finfo_t fi; |
| 536 | const char *savename; |
| 537 | |
| 538 | if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS))) { |
| 539 | return HTTP_FORBIDDEN; |
| 540 | } |
| 541 | |
| 542 | /* Save the name from the valid bits. */ |
| 543 | savename = (lfi->valid & APR_FINFO_NAME) ? lfi->name : NULL; |
| 544 | |
| 545 | /* if OPT_SYM_OWNER is unset, we only need to check target accessible */ |
| 546 | if (!(opts & OPT_SYM_OWNER)) { |
| 547 | if (apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME | APR_FINFO_LINK), p) |
| 548 | != APR_SUCCESS) |
| 549 | { |
| 550 | return HTTP_FORBIDDEN; |
| 551 | } |
| 552 | |
| 553 | /* Give back the target */ |
| 554 | memcpy(lfi, &fi, sizeof(fi)); |
| 555 | if (savename) { |
| 556 | lfi->name = savename; |
| 557 | lfi->valid |= APR_FINFO_NAME; |
| 558 | } |
| 559 | |
| 560 | return OK; |
| 561 | } |
| 562 | |
| 563 | /* OPT_SYM_OWNER only works if we can get the owner of |
| 564 | * both the file and symlink. First fill in a missing |
| 565 | * owner of the symlink, then get the info of the target. |
| 566 | */ |
| 567 | if (!(lfi->valid & APR_FINFO_OWNER)) { |
| 568 | if (apr_stat(lfi, d, lfi->valid | APR_FINFO_LINK | APR_FINFO_OWNER, p) |
| 569 | != APR_SUCCESS) |
| 570 | { |
| 571 | return HTTP_FORBIDDEN; |
| 572 | } |
| 573 | } |
| 574 | |
| 575 | if (apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME), p) != APR_SUCCESS) { |
| 576 | return HTTP_FORBIDDEN; |
| 577 | } |
| 578 | |
| 579 | if (apr_uid_compare(fi.user, lfi->user) != APR_SUCCESS) { |
| 580 | return HTTP_FORBIDDEN; |
| 581 | } |
| 582 | |
| 583 | /* Give back the target */ |
| 584 | memcpy(lfi, &fi, sizeof(fi)); |
| 585 | if (savename) { |
| 586 | lfi->name = savename; |
| 587 | lfi->valid |= APR_FINFO_NAME; |
| 588 | } |
| 589 | |
| 590 | return OK; |
no outgoing calls
no test coverage detected