Use alternative code (also from BusyBox) for checking if the user is in a group, avoiding a call to getgroups(), which isn't supported.

This could actually be further simplified, since GNO doesn't really have group-based file permissions, but I'll leave that until later.
This commit is contained in:
Stephen Heumann 2014-11-04 16:24:41 -06:00
parent a60c64d6c7
commit 7e5a584f0c
3 changed files with 20 additions and 49 deletions

View File

@ -390,8 +390,6 @@ struct test_statics {
/* set only by check_operator(), either to bogus struct
* or points to matching operator_t struct. Never NULL. */
const struct operator_t *last_operator;
gid_t *group_array;
int ngroups;
jmp_buf leaving;
};
@ -401,8 +399,6 @@ extern struct test_statics *const test_ptr_to_statics;
#define S (*test_ptr_to_statics)
#define args (S.args )
#define last_operator (S.last_operator)
#define group_array (S.group_array )
#define ngroups (S.ngroups )
#define leaving (S.leaving )
#define INIT_S() do { \
@ -561,46 +557,14 @@ static int binop(void)
}
static void initialize_group_array(void)
{
int n;
/* 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. */
//XXX: FIXME: duplicate of existing libbb function?
// see toplevel TODO file:
// possible code duplication ingroup() and is_a_group_member()
static int is_a_group_member(gid_t gid)
{
int i;
/* Short-circuit if possible, maybe saving a call to getgroups(). */
/* Short-circuit if possible */
if (gid == getgid() || gid == getegid())
return 1;
if (ngroups == 0)
initialize_group_array();
/* Search through the list looking for GID. */
for (i = 0; i < ngroups; i++)
if (gid == group_array[i])
return 1;
return 0;
return ingroup(getuid(), gid) || ingroup(geteuid(), gid);
}
@ -863,16 +827,6 @@ int test_main(int argc, char **argv)
if (res)
goto ret;
/* resetting ngroups is probably unnecessary. it will
* force a new call to getgroups(), which prevents using
* group data fetched during a previous call. but the
* only way the group data could be stale is if there's
* been an intervening call to setgroups(), and this
* isn't likely in the case of a shell. paranoia
* prevails...
*/
/*ngroups = 0; - done by INIT_S() */
argv++;
args = argv;

View File

@ -841,6 +841,8 @@ void die_if_bad_username(const char* name) FAST_FUNC;
#define die_if_bad_username(name) ((void)(name))
#endif
int ingroup(uid_t u, gid_t g);
#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 update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname);

View File

@ -18,3 +18,18 @@ void FAST_FUNC bb_show_usage(void)
{
xfunc_die();
}
/* check if u is member of group g */
int ingroup(uid_t u, gid_t g)
{
struct group *grp = getgrgid(g);
if (grp) {
char **mem;
for (mem = grp->gr_mem; *mem; mem++) {
struct passwd *pwd = getpwnam(*mem);
if (pwd && (pwd->pw_uid == u))
return 1;
}
}
return 0;
}