diff options
| author | Ron Yorston <rmy@pobox.com> | 2024-10-08 08:46:53 +0100 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2024-10-08 08:47:44 +0100 |
| commit | 2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de (patch) | |
| tree | 3d907c63f92be35ef96dde01fedf6cf6b7a8e14c /coreutils | |
| parent | 5b30de8fba414f75cb25faebf5cd8f391e1deb75 (diff) | |
| parent | 0929a129fc75c556de67877491281e0bc3ef3edd (diff) | |
| download | busybox-w32-2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de.tar.gz busybox-w32-2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de.tar.bz2 busybox-w32-2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de.zip | |
Merge branch 'busybox' into merge
Diffstat (limited to 'coreutils')
| -rw-r--r-- | coreutils/test.c | 91 |
1 files changed, 47 insertions, 44 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index 008d90b25..b63e33cc0 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
| @@ -426,8 +426,7 @@ struct test_statics { | |||
| 426 | /* set only by check_operator(), either to bogus struct | 426 | /* set only by check_operator(), either to bogus struct |
| 427 | * or points to matching operator_t struct. Never NULL. */ | 427 | * or points to matching operator_t struct. Never NULL. */ |
| 428 | const struct operator_t *last_operator; | 428 | const struct operator_t *last_operator; |
| 429 | gid_t *group_array; | 429 | struct cached_groupinfo *groupinfo; |
| 430 | int ngroups; | ||
| 431 | #if BASH_TEST2 | 430 | #if BASH_TEST2 |
| 432 | bool bash_test2; | 431 | bool bash_test2; |
| 433 | #endif | 432 | #endif |
| @@ -440,8 +439,7 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; | |||
| 440 | #define S (*test_ptr_to_statics) | 439 | #define S (*test_ptr_to_statics) |
| 441 | #define args (S.args ) | 440 | #define args (S.args ) |
| 442 | #define last_operator (S.last_operator) | 441 | #define last_operator (S.last_operator) |
| 443 | #define group_array (S.group_array ) | 442 | #define groupinfo (S.groupinfo ) |
| 444 | #define ngroups (S.ngroups ) | ||
| 445 | #define bash_test2 (S.bash_test2 ) | 443 | #define bash_test2 (S.bash_test2 ) |
| 446 | #define leaving (S.leaving ) | 444 | #define leaving (S.leaving ) |
| 447 | 445 | ||
| @@ -449,7 +447,6 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; | |||
| 449 | XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ | 447 | XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ |
| 450 | } while (0) | 448 | } while (0) |
| 451 | #define DEINIT_S() do { \ | 449 | #define DEINIT_S() do { \ |
| 452 | free(group_array); \ | ||
| 453 | free(test_ptr_to_statics); \ | 450 | free(test_ptr_to_statics); \ |
| 454 | } while (0) | 451 | } while (0) |
| 455 | 452 | ||
| @@ -637,62 +634,52 @@ static int binop(void) | |||
| 637 | /*return 1; - NOTREACHED */ | 634 | /*return 1; - NOTREACHED */ |
| 638 | } | 635 | } |
| 639 | 636 | ||
| 640 | static void initialize_group_array(void) | ||
| 641 | { | ||
| 642 | group_array = bb_getgroups(&ngroups, NULL); | ||
| 643 | } | ||
| 644 | |||
| 645 | /* Return non-zero if GID is one that we have in our groups list. */ | 637 | /* Return non-zero if GID is one that we have in our groups list. */ |
| 646 | //XXX: FIXME: duplicate of existing libbb function? | ||
| 647 | // see toplevel TODO file: | ||
| 648 | // possible code duplication ingroup() and is_a_group_member() | ||
| 649 | static int is_a_group_member(gid_t gid) | 638 | static int is_a_group_member(gid_t gid) |
| 650 | { | 639 | { |
| 651 | int i; | ||
| 652 | |||
| 653 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ | 640 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ |
| 654 | if (gid == getgid() || gid == getegid()) | 641 | if (gid == get_cached_egid(&groupinfo->egid)) |
| 655 | return 1; | 642 | return 1; |
| 656 | 643 | ||
| 657 | if (ngroups == 0) | 644 | return is_in_supplementary_groups(groupinfo, gid); |
| 658 | initialize_group_array(); | ||
| 659 | |||
| 660 | /* Search through the list looking for GID. */ | ||
| 661 | for (i = 0; i < ngroups; i++) | ||
| 662 | if (gid == group_array[i]) | ||
| 663 | return 1; | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | 645 | } |
| 667 | 646 | ||
| 668 | 647 | /* | |
| 669 | /* Do the same thing access(2) does, but use the effective uid and gid, | 648 | * Similar to what access(2) does, but uses the effective uid and gid. |
| 670 | and don't make the mistake of telling root that any file is | 649 | * Doesn't make the mistake of telling root that any file is executable. |
| 671 | executable. */ | 650 | * Returns non-zero if the file is accessible. |
| 672 | static int test_eaccess(struct stat *st, int mode) | 651 | */ |
| 652 | static int test_st_mode(struct stat *st, int mode) | ||
| 673 | { | 653 | { |
| 674 | unsigned int euid = geteuid(); | 654 | enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; |
| 655 | unsigned euid; | ||
| 656 | |||
| 657 | if (mode == X_OK) { | ||
| 658 | /* Do we already know with no extra syscalls? */ | ||
| 659 | //if (!S_ISREG(st->st_mode)) | ||
| 660 | // return 0; /* not a regular file */ | ||
| 661 | // ^^^ bash 5.2.15 "test -x" does not check this! | ||
| 662 | if ((st->st_mode & ANY_IX) == 0) | ||
| 663 | return 0; /* no one can execute */ | ||
| 664 | if ((st->st_mode & ANY_IX) == ANY_IX) | ||
| 665 | return 1; /* anyone can execute */ | ||
| 666 | } | ||
| 675 | 667 | ||
| 668 | euid = get_cached_euid(&groupinfo->euid); | ||
| 676 | if (euid == 0) { | 669 | if (euid == 0) { |
| 677 | /* Root can read or write any file. */ | 670 | /* Root can read or write any file. */ |
| 678 | if (mode != X_OK) | 671 | if (mode != X_OK) |
| 679 | return 0; | 672 | return 1; |
| 680 | 673 | ||
| 681 | /* Root can execute any file that has any one of the execute | 674 | /* Root can execute any file that has any one of the execute |
| 682 | * bits set. */ | 675 | * bits set. */ |
| 683 | if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) | 676 | mode = S_IXUSR | S_IXGRP | S_IXOTH; |
| 684 | return 0; | 677 | } else if (st->st_uid == euid) /* owner */ |
| 685 | } | ||
| 686 | |||
| 687 | if (st->st_uid == euid) /* owner */ | ||
| 688 | mode <<= 6; | 678 | mode <<= 6; |
| 689 | else if (is_a_group_member(st->st_gid)) | 679 | else if (is_a_group_member(st->st_gid)) |
| 690 | mode <<= 3; | 680 | mode <<= 3; |
| 691 | 681 | ||
| 692 | if (st->st_mode & mode) | 682 | return st->st_mode & mode; |
| 693 | return 0; | ||
| 694 | |||
| 695 | return -1; | ||
| 696 | } | 683 | } |
| 697 | 684 | ||
| 698 | 685 | ||
| @@ -722,7 +709,7 @@ static int filstat(char *nm, enum token mode) | |||
| 722 | i = W_OK; | 709 | i = W_OK; |
| 723 | if (mode == FILEX) | 710 | if (mode == FILEX) |
| 724 | i = X_OK; | 711 | i = X_OK; |
| 725 | return test_eaccess(&s, i) == 0; | 712 | return test_st_mode(&s, i); |
| 726 | } | 713 | } |
| 727 | if (is_file_type(mode)) { | 714 | if (is_file_type(mode)) { |
| 728 | if (mode == FILREG) | 715 | if (mode == FILREG) |
| @@ -760,7 +747,7 @@ static int filstat(char *nm, enum token mode) | |||
| 760 | return ((s.st_mode & i) != 0); | 747 | return ((s.st_mode & i) != 0); |
| 761 | } | 748 | } |
| 762 | if (mode == FILGZ) | 749 | if (mode == FILGZ) |
| 763 | return s.st_size > 0L; | 750 | return s.st_size != 0L; /* shorter than "> 0" test */ |
| 764 | if (mode == FILUID) | 751 | if (mode == FILUID) |
| 765 | return s.st_uid == geteuid(); | 752 | return s.st_uid == geteuid(); |
| 766 | if (mode == FILGID) | 753 | if (mode == FILGID) |
| @@ -891,7 +878,7 @@ static number_t primary(enum token n) | |||
| 891 | } | 878 | } |
| 892 | 879 | ||
| 893 | 880 | ||
| 894 | int test_main(int argc, char **argv) | 881 | int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv) |
| 895 | { | 882 | { |
| 896 | int res; | 883 | int res; |
| 897 | const char *arg0; | 884 | const char *arg0; |
| @@ -924,6 +911,7 @@ int test_main(int argc, char **argv) | |||
| 924 | 911 | ||
| 925 | /* We must do DEINIT_S() prior to returning */ | 912 | /* We must do DEINIT_S() prior to returning */ |
| 926 | INIT_S(); | 913 | INIT_S(); |
| 914 | groupinfo = pgroupinfo; | ||
| 927 | 915 | ||
| 928 | #if BASH_TEST2 | 916 | #if BASH_TEST2 |
| 929 | bash_test2 = bt2; | 917 | bash_test2 = bt2; |
| @@ -1026,3 +1014,18 @@ int test_main(int argc, char **argv) | |||
| 1026 | DEINIT_S(); | 1014 | DEINIT_S(); |
| 1027 | return res; | 1015 | return res; |
| 1028 | } | 1016 | } |
| 1017 | |||
| 1018 | int test_main(int argc, char **argv) | ||
| 1019 | { | ||
| 1020 | struct cached_groupinfo info; | ||
| 1021 | int r; | ||
| 1022 | |||
| 1023 | info.euid = -1; | ||
| 1024 | info.egid = -1; | ||
| 1025 | info.ngroups = 0; | ||
| 1026 | info.supplementary_array = NULL; | ||
| 1027 | r = test_main2(&info, argc, argv); | ||
| 1028 | free(info.supplementary_array); | ||
| 1029 | |||
| 1030 | return r; | ||
| 1031 | } | ||
