comparison src/core/ngx_open_file_cache.c @ 4480:5a3cb84545e5

Disable symlinks: fixed edge cases of path handling. This includes non-absolute pathnames, multiple slashes and trailing slashes. In collaboration with Valentin Bartenev.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 15 Feb 2012 12:18:55 +0000
parents 5e6436812c9a
children f78a29a2f9e6
comparison
equal deleted inserted replaced
4479:5e6436812c9a 4480:5a3cb84545e5
560 560
561 return fd; 561 return fd;
562 562
563 #else 563 #else
564 564
565 u_char *p, *cp, *end; 565 u_char *p, *cp, *end;
566 ngx_fd_t at_fd; 566 ngx_fd_t at_fd;
567 ngx_str_t at_name; 567 ngx_str_t at_name;
568 ngx_file_info_t fi;
568 569
569 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { 570 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
570 fd = ngx_open_file(name->data, mode, create, access); 571 fd = ngx_open_file(name->data, mode, create, access);
571 572
572 if (fd == NGX_INVALID_FILE) { 573 if (fd == NGX_INVALID_FILE) {
576 } 577 }
577 578
578 return fd; 579 return fd;
579 } 580 }
580 581
581 at_fd = ngx_openat_file(AT_FDCWD, "/", NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, 582 p = name->data;
582 NGX_FILE_OPEN, 0); 583 end = p + name->len;
583 584
584 if (at_fd == NGX_INVALID_FILE) { 585 at_fd = AT_FDCWD;
585 of->err = ngx_errno;
586 of->failed = ngx_openat_file_n;
587 return NGX_INVALID_FILE;
588 }
589
590 at_name = *name; 586 at_name = *name;
591 at_name.len = 1; 587
592 588 if (p[0] == '/') {
593 end = name->data + name->len; 589 at_fd = ngx_openat_file(at_fd, "/",
594 p = name->data + 1; 590 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
591 NGX_FILE_OPEN, 0);
592
593 if (at_fd == NGX_FILE_ERROR) {
594 of->err = ngx_errno;
595 of->failed = ngx_openat_file_n;
596 return NGX_FILE_ERROR;
597 }
598
599 at_name.len = 1;
600 p++;
601 }
595 602
596 for ( ;; ) { 603 for ( ;; ) {
597 cp = ngx_strlchr(p, end, '/'); 604 cp = ngx_strlchr(p, end, '/');
598 if (cp == NULL) { 605 if (cp == NULL) {
599 break; 606 break;
600 } 607 }
601 608
609 if (cp == p) {
610 p++;
611 continue;
612 }
613
602 *cp = '\0'; 614 *cp = '\0';
603 615
604 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { 616 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
605 fd = ngx_openat_file_owner(at_fd, p, 617 fd = ngx_openat_file_owner(at_fd, p,
606 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, 618 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
626 } 638 }
627 639
628 p = cp + 1; 640 p = cp + 1;
629 at_fd = fd; 641 at_fd = fd;
630 at_name.len = cp - at_name.data; 642 at_name.len = cp - at_name.data;
643 }
644
645 if (p == end && at_fd != AT_FDCWD) {
646
647 /*
648 * If pathname ends with a trailing slash, check if last path
649 * component is a directory; if not, fail with ENOTDIR as per
650 * POSIX.
651 *
652 * We use separate check instead of O_DIRECTORY in the loop above,
653 * as O_DIRECTORY doesn't work on FreeBSD 8.
654 *
655 * Note this returns already opened file descriptor, with different
656 * mode/create/access. This is believed to be safe as we don't
657 * use this codepath to create directories.
658 */
659
660 if (ngx_fd_info(at_fd, &fi) == NGX_FILE_ERROR) {
661 of->err = ngx_errno;
662 of->failed = ngx_fd_info_n;
663 fd = NGX_INVALID_FILE;
664
665 goto failed;
666 }
667
668 if (ngx_is_dir(&fi)) {
669 return at_fd;
670 }
671
672 of->err = ENOTDIR;
673 of->failed = ngx_openat_file_n;
674 fd = NGX_INVALID_FILE;
675
676 goto failed;
631 } 677 }
632 678
633 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { 679 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
634 fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log); 680 fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log);
635 681