21 | 21 |
|
22 | 22 |
|
23 | 23 |
static void ngx_open_file_cache_cleanup(void *data);
|
|
24 |
#if (NGX_HAVE_OPENAT)
|
|
25 |
static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
|
|
26 |
ngx_int_t mode, ngx_int_t create, ngx_int_t access);
|
|
27 |
#endif
|
|
28 |
static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name,
|
|
29 |
ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create,
|
|
30 |
ngx_int_t access);
|
|
31 |
static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name,
|
|
32 |
ngx_open_file_info_t *of, ngx_file_info_t *fi);
|
24 | 33 |
static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name,
|
25 | 34 |
ngx_open_file_info_t *of, ngx_log_t *log);
|
26 | 35 |
static void ngx_open_file_add_event(ngx_open_file_cache_t *cache,
|
|
146 | 155 |
|
147 | 156 |
if (of->test_only) {
|
148 | 157 |
|
149 | |
if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
|
150 | |
of->err = ngx_errno;
|
151 | |
of->failed = ngx_file_info_n;
|
|
158 |
if (ngx_file_info_wrapper(name, of, &fi) == NGX_FILE_ERROR) {
|
152 | 159 |
return NGX_ERROR;
|
153 | 160 |
}
|
154 | 161 |
|
|
216 | 223 |
if (file->use_event
|
217 | 224 |
|| (file->event == NULL
|
218 | 225 |
&& (of->uniq == 0 || of->uniq == file->uniq)
|
219 | |
&& now - file->created < of->valid))
|
|
226 |
&& now - file->created < of->valid
|
|
227 |
#if (NGX_HAVE_OPENAT)
|
|
228 |
&& of->disable_symlinks == file->disable_symlinks
|
|
229 |
#endif
|
|
230 |
))
|
220 | 231 |
{
|
221 | 232 |
if (file->err == 0) {
|
222 | 233 |
|
|
238 | 249 |
|
239 | 250 |
} else {
|
240 | 251 |
of->err = file->err;
|
|
252 |
#if (NGX_HAVE_OPENAT)
|
|
253 |
of->failed = file->disable_symlinks ? ngx_openat_file_n
|
|
254 |
: ngx_open_file_n;
|
|
255 |
#else
|
241 | 256 |
of->failed = ngx_open_file_n;
|
|
257 |
#endif
|
242 | 258 |
}
|
243 | 259 |
|
244 | 260 |
goto found;
|
|
374 | 390 |
|
375 | 391 |
file->fd = of->fd;
|
376 | 392 |
file->err = of->err;
|
|
393 |
#if (NGX_HAVE_OPENAT)
|
|
394 |
file->disable_symlinks = of->disable_symlinks;
|
|
395 |
#endif
|
377 | 396 |
|
378 | 397 |
if (of->err == 0) {
|
379 | 398 |
file->uniq = of->uniq;
|
|
458 | 477 |
}
|
459 | 478 |
|
460 | 479 |
|
|
480 |
#if (NGX_HAVE_OPENAT)
|
|
481 |
|
|
482 |
static ngx_fd_t
|
|
483 |
ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
|
|
484 |
ngx_int_t mode, ngx_int_t create, ngx_int_t access)
|
|
485 |
{
|
|
486 |
ngx_fd_t fd;
|
|
487 |
ngx_file_info_t fi, atfi;
|
|
488 |
|
|
489 |
/*
|
|
490 |
* To allow symlinks with the same owner, use openat() (followed
|
|
491 |
* by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare
|
|
492 |
* uids between fstat() and fstatat().
|
|
493 |
*
|
|
494 |
* As there is a race between openat() and fstatat() we don't
|
|
495 |
* know if openat() in fact opened symlink or not. Therefore,
|
|
496 |
* we have to compare uids even if fstatat() reports the opened
|
|
497 |
* component isn't a symlink (as we don't know whether it was
|
|
498 |
* symlink during openat() or not).
|
|
499 |
*/
|
|
500 |
|
|
501 |
fd = ngx_openat_file(at_fd, name, mode, create, access);
|
|
502 |
|
|
503 |
if (fd == NGX_FILE_ERROR) {
|
|
504 |
return NGX_FILE_ERROR;
|
|
505 |
}
|
|
506 |
|
|
507 |
if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW)
|
|
508 |
== NGX_FILE_ERROR)
|
|
509 |
{
|
|
510 |
ngx_close_file(fd);
|
|
511 |
return NGX_FILE_ERROR;
|
|
512 |
}
|
|
513 |
|
|
514 |
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
|
|
515 |
ngx_close_file(fd);
|
|
516 |
return NGX_FILE_ERROR;
|
|
517 |
}
|
|
518 |
|
|
519 |
if (fi.st_uid != atfi.st_uid) {
|
|
520 |
ngx_close_file(fd);
|
|
521 |
ngx_set_errno(NGX_ELOOP);
|
|
522 |
return NGX_FILE_ERROR;
|
|
523 |
}
|
|
524 |
|
|
525 |
return fd;
|
|
526 |
}
|
|
527 |
|
|
528 |
#endif
|
|
529 |
|
|
530 |
|
|
531 |
static ngx_fd_t
|
|
532 |
ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
|
|
533 |
ngx_int_t mode, ngx_int_t create, ngx_int_t access)
|
|
534 |
{
|
|
535 |
ngx_fd_t fd;
|
|
536 |
|
|
537 |
#if !(NGX_HAVE_OPENAT)
|
|
538 |
|
|
539 |
fd = ngx_open_file(name->data, mode, create, access);
|
|
540 |
|
|
541 |
if (fd == NGX_FILE_ERROR) {
|
|
542 |
of->err = ngx_errno;
|
|
543 |
of->failed = ngx_open_file_n;
|
|
544 |
return NGX_FILE_ERROR;
|
|
545 |
}
|
|
546 |
|
|
547 |
return fd;
|
|
548 |
|
|
549 |
#else
|
|
550 |
|
|
551 |
u_char *p, *cp, *end;
|
|
552 |
ngx_fd_t at_fd;
|
|
553 |
|
|
554 |
if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
|
|
555 |
fd = ngx_open_file(name->data, mode, create, access);
|
|
556 |
|
|
557 |
if (fd == NGX_FILE_ERROR) {
|
|
558 |
of->err = ngx_errno;
|
|
559 |
of->failed = ngx_open_file_n;
|
|
560 |
return NGX_FILE_ERROR;
|
|
561 |
}
|
|
562 |
|
|
563 |
return fd;
|
|
564 |
}
|
|
565 |
|
|
566 |
at_fd = ngx_openat_file(AT_FDCWD, "/", NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
|
|
567 |
NGX_FILE_OPEN, 0);
|
|
568 |
|
|
569 |
if (at_fd == NGX_FILE_ERROR) {
|
|
570 |
of->err = ngx_errno;
|
|
571 |
of->failed = ngx_openat_file_n;
|
|
572 |
return NGX_FILE_ERROR;
|
|
573 |
}
|
|
574 |
|
|
575 |
end = name->data + name->len;
|
|
576 |
p = name->data + 1;
|
|
577 |
|
|
578 |
for ( ;; ) {
|
|
579 |
cp = ngx_strlchr(p, end, '/');
|
|
580 |
if (cp == NULL) {
|
|
581 |
break;
|
|
582 |
}
|
|
583 |
|
|
584 |
*cp = '\0';
|
|
585 |
|
|
586 |
if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
|
|
587 |
fd = ngx_openat_file_owner(at_fd, p,
|
|
588 |
NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
|
|
589 |
NGX_FILE_OPEN, 0);
|
|
590 |
|
|
591 |
} else {
|
|
592 |
fd = ngx_openat_file(at_fd, p,
|
|
593 |
NGX_FILE_RDONLY|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW,
|
|
594 |
NGX_FILE_OPEN, 0);
|
|
595 |
}
|
|
596 |
|
|
597 |
*cp = '/';
|
|
598 |
|
|
599 |
ngx_close_file(at_fd);
|
|
600 |
|
|
601 |
if (fd == NGX_FILE_ERROR) {
|
|
602 |
of->err = ngx_errno;
|
|
603 |
of->failed = ngx_openat_file_n;
|
|
604 |
return NGX_FILE_ERROR;
|
|
605 |
}
|
|
606 |
|
|
607 |
p = cp + 1;
|
|
608 |
at_fd = fd;
|
|
609 |
}
|
|
610 |
|
|
611 |
if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
|
|
612 |
fd = ngx_openat_file_owner(at_fd, p, mode, create, access);
|
|
613 |
|
|
614 |
} else {
|
|
615 |
fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access);
|
|
616 |
}
|
|
617 |
|
|
618 |
if (fd == NGX_FILE_ERROR) {
|
|
619 |
of->err = ngx_errno;
|
|
620 |
of->failed = ngx_openat_file_n;
|
|
621 |
}
|
|
622 |
|
|
623 |
ngx_close_file(at_fd);
|
|
624 |
|
|
625 |
return fd;
|
|
626 |
#endif
|
|
627 |
}
|
|
628 |
|
|
629 |
|
|
630 |
static ngx_int_t
|
|
631 |
ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
|
|
632 |
ngx_file_info_t *fi)
|
|
633 |
{
|
|
634 |
ngx_int_t rc;
|
|
635 |
|
|
636 |
#if !(NGX_HAVE_OPENAT)
|
|
637 |
|
|
638 |
rc = ngx_file_info(name->data, fi);
|
|
639 |
|
|
640 |
if (rc == NGX_FILE_ERROR) {
|
|
641 |
of->err = ngx_errno;
|
|
642 |
of->failed = ngx_file_info_n;
|
|
643 |
return NGX_FILE_ERROR;
|
|
644 |
}
|
|
645 |
|
|
646 |
return rc;
|
|
647 |
|
|
648 |
#else
|
|
649 |
|
|
650 |
ngx_fd_t fd;
|
|
651 |
|
|
652 |
if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
|
|
653 |
|
|
654 |
rc = ngx_file_info(name->data, fi);
|
|
655 |
|
|
656 |
if (rc == NGX_FILE_ERROR) {
|
|
657 |
of->err = ngx_errno;
|
|
658 |
of->failed = ngx_file_info_n;
|
|
659 |
return NGX_FILE_ERROR;
|
|
660 |
}
|
|
661 |
|
|
662 |
return rc;
|
|
663 |
}
|
|
664 |
|
|
665 |
fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
|
|
666 |
NGX_FILE_OPEN, 0);
|
|
667 |
|
|
668 |
if (fd == NGX_FILE_ERROR) {
|
|
669 |
return NGX_FILE_ERROR;
|
|
670 |
}
|
|
671 |
|
|
672 |
if (ngx_fd_info(fd, fi) == NGX_FILE_ERROR) {
|
|
673 |
of->err = ngx_errno;
|
|
674 |
of->failed = ngx_fd_info_n;
|
|
675 |
ngx_close_file(fd);
|
|
676 |
return NGX_FILE_ERROR;
|
|
677 |
}
|
|
678 |
|
|
679 |
ngx_close_file(fd);
|
|
680 |
|
|
681 |
return NGX_OK;
|
|
682 |
#endif
|
|
683 |
}
|
|
684 |
|
|
685 |
|
461 | 686 |
static ngx_int_t
|
462 | 687 |
ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of,
|
463 | 688 |
ngx_log_t *log)
|
|
467 | 692 |
|
468 | 693 |
if (of->fd != NGX_INVALID_FILE) {
|
469 | 694 |
|
470 | |
if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
|
471 | |
of->failed = ngx_file_info_n;
|
472 | |
goto failed;
|
|
695 |
if (ngx_file_info_wrapper(name, of, &fi) == NGX_FILE_ERROR) {
|
|
696 |
of->fd = NGX_INVALID_FILE;
|
|
697 |
return NGX_ERROR;
|
473 | 698 |
}
|
474 | 699 |
|
475 | 700 |
if (of->uniq == ngx_file_uniq(&fi)) {
|
|
478 | 703 |
|
479 | 704 |
} else if (of->test_dir) {
|
480 | 705 |
|
481 | |
if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
|
482 | |
of->failed = ngx_file_info_n;
|
483 | |
goto failed;
|
|
706 |
if (ngx_file_info_wrapper(name, of, &fi) == NGX_FILE_ERROR) {
|
|
707 |
of->fd = NGX_INVALID_FILE;
|
|
708 |
return NGX_ERROR;
|
484 | 709 |
}
|
485 | 710 |
|
486 | 711 |
if (ngx_is_dir(&fi)) {
|
|
495 | 720 |
* This flag has no effect on a regular files.
|
496 | 721 |
*/
|
497 | 722 |
|
498 | |
fd = ngx_open_file(name->data, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
|
499 | |
NGX_FILE_OPEN, 0);
|
|
723 |
fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
|
|
724 |
NGX_FILE_OPEN, 0);
|
500 | 725 |
|
501 | 726 |
} else {
|
502 | |
fd = ngx_open_file(name->data, NGX_FILE_APPEND,
|
503 | |
NGX_FILE_CREATE_OR_OPEN,
|
504 | |
NGX_FILE_DEFAULT_ACCESS);
|
|
727 |
fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND,
|
|
728 |
NGX_FILE_CREATE_OR_OPEN,
|
|
729 |
NGX_FILE_DEFAULT_ACCESS);
|
505 | 730 |
}
|
506 | 731 |
|
507 | 732 |
if (fd == NGX_INVALID_FILE) {
|
508 | |
of->failed = ngx_open_file_n;
|
509 | |
goto failed;
|
|
733 |
of->fd = NGX_INVALID_FILE;
|
|
734 |
return NGX_ERROR;
|
510 | 735 |
}
|
511 | 736 |
|
512 | 737 |
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
|
|
564 | 789 |
of->is_exec = ngx_is_exec(&fi);
|
565 | 790 |
|
566 | 791 |
return NGX_OK;
|
567 | |
|
568 | |
failed:
|
569 | |
|
570 | |
of->fd = NGX_INVALID_FILE;
|
571 | |
of->err = ngx_errno;
|
572 | |
|
573 | |
return NGX_ERROR;
|
574 | 792 |
}
|
575 | 793 |
|
576 | 794 |
|