diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-04 18:49:24 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-04 18:56:45 +0200 |
commit | a8cf9c5a3ffd1601872d1ab14c5be00fde29209c (patch) | |
tree | 20d9accf1cfeeea31a7252f6d12889160cf3aab0 | |
parent | 6a3bcf340aa9d7defc86f21d75fd9412c5b9f427 (diff) | |
download | busybox-w32-a8cf9c5a3ffd1601872d1ab14c5be00fde29209c.tar.gz busybox-w32-a8cf9c5a3ffd1601872d1ab14c5be00fde29209c.tar.bz2 busybox-w32-a8cf9c5a3ffd1601872d1ab14c5be00fde29209c.zip |
libbb: new function bb_getgroups() - allocating wrapper around getgroups()
function old new delta
bb_getgroups - 111 +111
nexpr 843 757 -86
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 0/1 up/down: 111/-86) Total: 25 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/test.c | 33 | ||||
-rw-r--r-- | include/libbb.h | 9 | ||||
-rw-r--r-- | libbb/bb_getgroups.c | 47 |
3 files changed, 63 insertions, 26 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index edc625f57..edcf2a2d8 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -563,26 +563,11 @@ static int binop(void) | |||
563 | /*return 1; - NOTREACHED */ | 563 | /*return 1; - NOTREACHED */ |
564 | } | 564 | } |
565 | 565 | ||
566 | |||
567 | static void initialize_group_array(void) | 566 | static void initialize_group_array(void) |
568 | { | 567 | { |
569 | int n; | 568 | group_array = bb_getgroups(&ngroups, NULL); |
570 | |||
571 | /* getgroups may be expensive, try to use it only once */ | ||
572 | ngroups = 32; | ||
573 | do { | ||
574 | /* FIXME: ash tries so hard to not die on OOM, | ||
575 | * and we spoil it with just one xrealloc here */ | ||
576 | /* We realloc, because test_main can be entered repeatedly by shell. | ||
577 | * Testcase (ash): 'while true; do test -x some_file; done' | ||
578 | * and watch top. (some_file must have owner != you) */ | ||
579 | n = ngroups; | ||
580 | group_array = xrealloc(group_array, n * sizeof(gid_t)); | ||
581 | ngroups = getgroups(n, group_array); | ||
582 | } while (ngroups > n); | ||
583 | } | 569 | } |
584 | 570 | ||
585 | |||
586 | /* Return non-zero if GID is one that we have in our groups list. */ | 571 | /* Return non-zero if GID is one that we have in our groups list. */ |
587 | //XXX: FIXME: duplicate of existing libbb function? | 572 | //XXX: FIXME: duplicate of existing libbb function? |
588 | // see toplevel TODO file: | 573 | // see toplevel TODO file: |
@@ -610,14 +595,10 @@ static int is_a_group_member(gid_t gid) | |||
610 | /* Do the same thing access(2) does, but use the effective uid and gid, | 595 | /* Do the same thing access(2) does, but use the effective uid and gid, |
611 | and don't make the mistake of telling root that any file is | 596 | and don't make the mistake of telling root that any file is |
612 | executable. */ | 597 | executable. */ |
613 | static int test_eaccess(char *path, int mode) | 598 | static int test_eaccess(struct stat *st, int mode) |
614 | { | 599 | { |
615 | struct stat st; | ||
616 | unsigned int euid = geteuid(); | 600 | unsigned int euid = geteuid(); |
617 | 601 | ||
618 | if (stat(path, &st) < 0) | ||
619 | return -1; | ||
620 | |||
621 | if (euid == 0) { | 602 | if (euid == 0) { |
622 | /* Root can read or write any file. */ | 603 | /* Root can read or write any file. */ |
623 | if (mode != X_OK) | 604 | if (mode != X_OK) |
@@ -625,16 +606,16 @@ static int test_eaccess(char *path, int mode) | |||
625 | 606 | ||
626 | /* Root can execute any file that has any one of the execute | 607 | /* Root can execute any file that has any one of the execute |
627 | * bits set. */ | 608 | * bits set. */ |
628 | if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) | 609 | if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) |
629 | return 0; | 610 | return 0; |
630 | } | 611 | } |
631 | 612 | ||
632 | if (st.st_uid == euid) /* owner */ | 613 | if (st->st_uid == euid) /* owner */ |
633 | mode <<= 6; | 614 | mode <<= 6; |
634 | else if (is_a_group_member(st.st_gid)) | 615 | else if (is_a_group_member(st->st_gid)) |
635 | mode <<= 3; | 616 | mode <<= 3; |
636 | 617 | ||
637 | if (st.st_mode & mode) | 618 | if (st->st_mode & mode) |
638 | return 0; | 619 | return 0; |
639 | 620 | ||
640 | return -1; | 621 | return -1; |
@@ -667,7 +648,7 @@ static int filstat(char *nm, enum token mode) | |||
667 | i = W_OK; | 648 | i = W_OK; |
668 | if (mode == FILEX) | 649 | if (mode == FILEX) |
669 | i = X_OK; | 650 | i = X_OK; |
670 | return test_eaccess(nm, i) == 0; | 651 | return test_eaccess(&s, i) == 0; |
671 | } | 652 | } |
672 | if (is_file_type(mode)) { | 653 | if (is_file_type(mode)) { |
673 | if (mode == FILREG) | 654 | if (mode == FILREG) |
diff --git a/include/libbb.h b/include/libbb.h index 557978e66..1c9de3af0 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1033,6 +1033,15 @@ void die_if_bad_username(const char* name) FAST_FUNC; | |||
1033 | #else | 1033 | #else |
1034 | #define die_if_bad_username(name) ((void)(name)) | 1034 | #define die_if_bad_username(name) ((void)(name)) |
1035 | #endif | 1035 | #endif |
1036 | /* | ||
1037 | * Returns (-1) terminated malloced result of getgroups(). | ||
1038 | * Reallocs group_array (useful for repeated calls). | ||
1039 | * ngroups is an initial size of array. It is rounded up to 32 for realloc. | ||
1040 | * ngroups is updated on return. | ||
1041 | * ngroups can be NULL: bb_getgroups(NULL, NULL) is valid usage. | ||
1042 | * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). | ||
1043 | */ | ||
1044 | gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; | ||
1036 | 1045 | ||
1037 | #if ENABLE_FEATURE_UTMP | 1046 | #if ENABLE_FEATURE_UTMP |
1038 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); | 1047 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); |
diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c new file mode 100644 index 000000000..59ae53738 --- /dev/null +++ b/libbb/bb_getgroups.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Utility routines. | ||
3 | * | ||
4 | * Copyright (C) 2017 Denys Vlasenko | ||
5 | * | ||
6 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
7 | */ | ||
8 | |||
9 | //kbuild:lib-y += bb_getgroups.o | ||
10 | |||
11 | #include "libbb.h" | ||
12 | |||
13 | gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) | ||
14 | { | ||
15 | int n = ngroups ? *ngroups : 0; | ||
16 | |||
17 | /* getgroups may be a bit expensive, try to use it only once */ | ||
18 | if (n < 32) | ||
19 | n = 32; | ||
20 | |||
21 | for (;;) { | ||
22 | // FIXME: ash tries so hard to not die on OOM (when we are called from test), | ||
23 | // and we spoil it with just one xrealloc here | ||
24 | group_array = xrealloc(group_array, (n+1) * sizeof(group_array[0])); | ||
25 | n = getgroups(n, group_array); | ||
26 | /* | ||
27 | * If buffer is too small, kernel does not return new_n > n. | ||
28 | * It returns -1 and EINVAL: | ||
29 | */ | ||
30 | if (n >= 0) { | ||
31 | /* Terminator for bb_getgroups(NULL, NULL) usage */ | ||
32 | group_array[n] = (gid_t) -1; | ||
33 | break; | ||
34 | } | ||
35 | if (errno == EINVAL) { /* too small? */ | ||
36 | /* This is the way to ask kernel how big the array is */ | ||
37 | n = getgroups(0, group_array); | ||
38 | continue; | ||
39 | } | ||
40 | /* Some other error (should never happen on Linux) */ | ||
41 | bb_perror_msg_and_die("getgroups"); | ||
42 | } | ||
43 | |||
44 | if (ngroups) | ||
45 | *ngroups = n; | ||
46 | return group_array; | ||
47 | } | ||