aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-04 18:49:24 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-04 18:56:45 +0200
commita8cf9c5a3ffd1601872d1ab14c5be00fde29209c (patch)
tree20d9accf1cfeeea31a7252f6d12889160cf3aab0
parent6a3bcf340aa9d7defc86f21d75fd9412c5b9f427 (diff)
downloadbusybox-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.c33
-rw-r--r--include/libbb.h9
-rw-r--r--libbb/bb_getgroups.c47
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
567static void initialize_group_array(void) 566static 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. */
613static int test_eaccess(char *path, int mode) 598static 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 */
1044gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC;
1036 1045
1037#if ENABLE_FEATURE_UTMP 1046#if ENABLE_FEATURE_UTMP
1038void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); 1047void 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
13gid_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}