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>
This commit is contained in:
parent
6a3bcf340a
commit
a8cf9c5a3f
@ -563,26 +563,11 @@ static int binop(void)
|
|||||||
/*return 1; - NOTREACHED */
|
/*return 1; - NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void initialize_group_array(void)
|
static void initialize_group_array(void)
|
||||||
{
|
{
|
||||||
int n;
|
group_array = bb_getgroups(&ngroups, NULL);
|
||||||
|
|
||||||
/* getgroups may be expensive, try to use it only once */
|
|
||||||
ngroups = 32;
|
|
||||||
do {
|
|
||||||
/* FIXME: ash tries so hard to not die on OOM,
|
|
||||||
* and we spoil it with just one xrealloc here */
|
|
||||||
/* We realloc, because test_main can be entered repeatedly by shell.
|
|
||||||
* Testcase (ash): 'while true; do test -x some_file; done'
|
|
||||||
* and watch top. (some_file must have owner != you) */
|
|
||||||
n = ngroups;
|
|
||||||
group_array = xrealloc(group_array, n * sizeof(gid_t));
|
|
||||||
ngroups = getgroups(n, group_array);
|
|
||||||
} while (ngroups > n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return non-zero if GID is one that we have in our groups list. */
|
/* Return non-zero if GID is one that we have in our groups list. */
|
||||||
//XXX: FIXME: duplicate of existing libbb function?
|
//XXX: FIXME: duplicate of existing libbb function?
|
||||||
// see toplevel TODO file:
|
// see toplevel TODO file:
|
||||||
@ -610,14 +595,10 @@ static int is_a_group_member(gid_t gid)
|
|||||||
/* Do the same thing access(2) does, but use the effective uid and gid,
|
/* Do the same thing access(2) does, but use the effective uid and gid,
|
||||||
and don't make the mistake of telling root that any file is
|
and don't make the mistake of telling root that any file is
|
||||||
executable. */
|
executable. */
|
||||||
static int test_eaccess(char *path, int mode)
|
static int test_eaccess(struct stat *st, int mode)
|
||||||
{
|
{
|
||||||
struct stat st;
|
|
||||||
unsigned int euid = geteuid();
|
unsigned int euid = geteuid();
|
||||||
|
|
||||||
if (stat(path, &st) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (euid == 0) {
|
if (euid == 0) {
|
||||||
/* Root can read or write any file. */
|
/* Root can read or write any file. */
|
||||||
if (mode != X_OK)
|
if (mode != X_OK)
|
||||||
@ -625,16 +606,16 @@ static int test_eaccess(char *path, int mode)
|
|||||||
|
|
||||||
/* Root can execute any file that has any one of the execute
|
/* Root can execute any file that has any one of the execute
|
||||||
* bits set. */
|
* bits set. */
|
||||||
if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
|
if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.st_uid == euid) /* owner */
|
if (st->st_uid == euid) /* owner */
|
||||||
mode <<= 6;
|
mode <<= 6;
|
||||||
else if (is_a_group_member(st.st_gid))
|
else if (is_a_group_member(st->st_gid))
|
||||||
mode <<= 3;
|
mode <<= 3;
|
||||||
|
|
||||||
if (st.st_mode & mode)
|
if (st->st_mode & mode)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -667,7 +648,7 @@ static int filstat(char *nm, enum token mode)
|
|||||||
i = W_OK;
|
i = W_OK;
|
||||||
if (mode == FILEX)
|
if (mode == FILEX)
|
||||||
i = X_OK;
|
i = X_OK;
|
||||||
return test_eaccess(nm, i) == 0;
|
return test_eaccess(&s, i) == 0;
|
||||||
}
|
}
|
||||||
if (is_file_type(mode)) {
|
if (is_file_type(mode)) {
|
||||||
if (mode == FILREG)
|
if (mode == FILREG)
|
||||||
|
@ -1033,6 +1033,15 @@ void die_if_bad_username(const char* name) FAST_FUNC;
|
|||||||
#else
|
#else
|
||||||
#define die_if_bad_username(name) ((void)(name))
|
#define die_if_bad_username(name) ((void)(name))
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
* Returns (-1) terminated malloced result of getgroups().
|
||||||
|
* Reallocs group_array (useful for repeated calls).
|
||||||
|
* ngroups is an initial size of array. It is rounded up to 32 for realloc.
|
||||||
|
* ngroups is updated on return.
|
||||||
|
* ngroups can be NULL: bb_getgroups(NULL, NULL) is valid usage.
|
||||||
|
* Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call).
|
||||||
|
*/
|
||||||
|
gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC;
|
||||||
|
|
||||||
#if ENABLE_FEATURE_UTMP
|
#if ENABLE_FEATURE_UTMP
|
||||||
void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname);
|
void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname);
|
||||||
|
47
libbb/bb_getgroups.c
Normal file
47
libbb/bb_getgroups.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Utility routines.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Denys Vlasenko
|
||||||
|
*
|
||||||
|
* Licensed under GPLv2, see file LICENSE in this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//kbuild:lib-y += bb_getgroups.o
|
||||||
|
|
||||||
|
#include "libbb.h"
|
||||||
|
|
||||||
|
gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
|
||||||
|
{
|
||||||
|
int n = ngroups ? *ngroups : 0;
|
||||||
|
|
||||||
|
/* getgroups may be a bit expensive, try to use it only once */
|
||||||
|
if (n < 32)
|
||||||
|
n = 32;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// FIXME: ash tries so hard to not die on OOM (when we are called from test),
|
||||||
|
// and we spoil it with just one xrealloc here
|
||||||
|
group_array = xrealloc(group_array, (n+1) * sizeof(group_array[0]));
|
||||||
|
n = getgroups(n, group_array);
|
||||||
|
/*
|
||||||
|
* If buffer is too small, kernel does not return new_n > n.
|
||||||
|
* It returns -1 and EINVAL:
|
||||||
|
*/
|
||||||
|
if (n >= 0) {
|
||||||
|
/* Terminator for bb_getgroups(NULL, NULL) usage */
|
||||||
|
group_array[n] = (gid_t) -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (errno == EINVAL) { /* too small? */
|
||||||
|
/* This is the way to ask kernel how big the array is */
|
||||||
|
n = getgroups(0, group_array);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Some other error (should never happen on Linux) */
|
||||||
|
bb_perror_msg_and_die("getgroups");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngroups)
|
||||||
|
*ngroups = n;
|
||||||
|
return group_array;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user