Hi,
i'm posting a drop in replacement for id that summarizes my current progress
in making id SuSv3 compliant and in a working implementation of
llist *bb_getgrouplist(). The latter at the moment is not using parse_config
stuff as in my tests in this specific case it led to bigger size, but this
could be due to
my limited skills. Please help me stress test id in the numerous corner cases
that arise in various using conditions like:
chown tito.tito busybox
chmod u+s,g+s busybox
(BTW: a testsuite would be a GOOD THING(TM))
size currently is:
size id.o
text data bss dec hex filename
986 0 0 986 3da id.o
Best regards and thanks for your time and effort,
Ciao,
Tito
/* vi: set sw=4 ts=4: */
/*
* Mini id implementation for busybox
*
* Copyright (C) 2000 by Randolph Chung <[EMAIL PROTECTED]>
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant. */
/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever length and to
* be more similar to GNU id.
* -Z option support: by Yuichi Nakamura <[EMAIL PROTECTED]>
* Added -G option Tito Ragusa (C) 2008 for SUSv3.
*/
#include "libbb.h"
#define PRINT_REAL 1
#define NAME_NOT_NUMBER 2
#define JUST_USER 4
#define JUST_GROUP 8
#define JUST_ALL_GROUPS 16
#if ENABLE_SELINUX
#define JUST_CONTEXT 32
#endif
static int printf_full(unsigned id, const char *arg, const char *prefix)
{
const char *fmt = "%s%u";
int status = EXIT_FAILURE;
if (arg) {
fmt = "%s%u(%s)";
status = EXIT_SUCCESS;
}
printf(fmt, prefix, id, arg);
return status;
}
static short print_list_helper(const char *fmt, gid_t gid, const char* prefix, unsigned flags)
{
if (flags) /* -G */
printf(fmt, (flags & NAME_NOT_NUMBER) ? bb_getgrgid(NULL, -1, gid) : itoa(gid));
else /* Default mode */
return printf_full(gid, bb_getgrgid(NULL, 0, gid), prefix);
return EXIT_SUCCESS;
}
static short print_group_list(llist_t *grp_list, unsigned flags)
{
short status = EXIT_SUCCESS;
gid_t *gid = llist_pop(&grp_list);
status |= print_list_helper("%s", *gid, " groups=", flags);
if (ENABLE_FEATURE_CLEAN_UP)
free(gid);
while (grp_list) {
gid = llist_pop(&grp_list);
status |= print_list_helper(" %s", *gid, ",", flags);
if (ENABLE_FEATURE_CLEAN_UP)
free(gid);
}
if (ENABLE_FEATURE_CLEAN_UP)
free(grp_list);
return status;
}
static llist_t *bb_getgrouplist_malloc(uid_t ruid, gid_t rgid, gid_t egid, int flags)
{
FILE *group_file;
struct passwd *pwd;
struct group *grp;
llist_t *group_list = NULL;
char *line;
pwd = getpwuid(ruid);
group_file = fopen_or_warn(bb_path_group_file, "r");
if (group_file && pwd) {
llist_add_to_end(&group_list, memcpy(xmalloc(sizeof(gid_t)), &(rgid), sizeof(gid_t)));
if (flags && rgid != egid) {
llist_add_to_end(&group_list, memcpy(xmalloc(sizeof(gid_t)), &egid, sizeof(gid_t)));
}
/* Walk through /etc/group */
while ((line = xmalloc_fgetline(group_file)) != NULL) {
/* Get the group name token and obtain a struct group */
/* rather than try to parse the whole line */
/* This should not fail unless group is removed after */
/* we read the line. We can ignore it */
grp = getgrnam(strtok(line, ":"));
/* Check if we have this one already */
if (grp && grp->gr_gid != pwd->pw_gid) {
/* Walk through the group members */
while (*(grp->gr_mem)) {
/* Are we a member of this group? */
if (!strcmp(pwd->pw_name, *(grp->gr_mem))) {
/* Found, add the gid to the list */
llist_add_to_end(&group_list, memcpy(xmalloc(sizeof(gid_t)), &(grp->gr_gid), sizeof(gid_t)));
/* No need to continue the search, cannot be list member twice */
break;
}
/* Next group member */
(grp->gr_mem)++;
}
}
/* Clean up */
if (ENABLE_FEATURE_CLEAN_UP)
free(line);
}
/* Clean up */
if (ENABLE_FEATURE_CLEAN_UP)
fclose(group_file);
}
/* return list or NULL on error */
return group_list;
}
int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int id_main(int argc UNUSED_PARAM, char **argv)
{
struct passwd *p;
uid_t ruid;
gid_t rgid;
uid_t euid;
gid_t egid;
llist_t *grplist;
unsigned flags;
short status = EXIT_SUCCESS;
//int ngrp = 0;
#if ENABLE_SELINUX
security_context_t scontext;
#endif
/* Don't allow -n -r -nr -ug -uG -gG -rug -nug -rnug */
/* Don't allow more than one username */
opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" USE_SELINUX(":u--Z:Z--u:g--Z:Z--g");
flags = getopt32(argv, "rnugG" USE_SELINUX("Z"));
/* This values could be overwritten later */
euid = geteuid();
egid = getegid();
ruid = getuid();
rgid = getgid();
if (argv[optind]) {
p = getpwnam(argv[optind]);
/* xuname2uid is needed because it exits on failure */
euid = ruid = xuname2uid(argv[optind]);
egid = rgid = p->pw_gid;
/* in this case PRINT_REAL is the same */
}
if (flags & JUST_ALL_GROUPS) {
/* Ignore return value, exits on failure */
grplist = bb_getgrouplist_malloc(ruid, rgid, egid, flags);
status |= print_group_list(grplist, flags);
bb_putchar('\n');
/* exit */
fflush_stdout_and_exit(status);
}
if (flags & (JUST_GROUP | JUST_USER USE_SELINUX(| JUST_CONTEXT))) {
/* JUST_GROUP and JUST_USER are mutually exclusive */
if (flags & NAME_NOT_NUMBER) {
/* bb_getXXXid(-1) exits on failure, puts cannot segfault */
puts((flags & JUST_USER) ? bb_getpwuid(NULL, -1, ruid) : bb_getgrgid(NULL, -1, rgid));
} else {
printf("%u\n", (flags & JUST_USER) ? ruid : rgid);
}
#if ENABLE_SELINUX
if (flags & JUST_CONTEXT) {
selinux_or_die();
if (argv[optind]) {
bb_error_msg_and_die("user name can't be passed with -Z");
}
if (getcon(&scontext)) {
bb_error_msg_and_die("can't get process context");
}
puts(scontext);
}
#endif
/* exit */
fflush_stdout_and_exit(EXIT_SUCCESS);
}
/* Print full info like GNU id */
/* bb_getpwuid(0) doesn't exit on failure (returns NULL) */
status = printf_full(ruid, bb_getpwuid(NULL, 0, ruid), "uid=");
status |= printf_full(rgid, bb_getgrgid(NULL, 0, rgid), " gid=");
if (ruid != euid)
status = printf_full(euid, bb_getpwuid(NULL, 0, euid), " euid=");
if (rgid != egid)
status |= printf_full(egid, bb_getgrgid(NULL, 0, egid), " egid=");
grplist = bb_getgrouplist_malloc(ruid, rgid, egid, flags);
status |= print_group_list(grplist, 0);
#if ENABLE_SELINUX
if (is_selinux_enabled()) {
security_context_t mysid;
getcon(&mysid);
printf(" context=%s", mysid ? mysid : "unknown");
if (mysid) /* TODO: maybe freecon(NULL) is harmless? */
freecon(mysid);
}
#endif
bb_putchar('\n');
fflush_stdout_and_exit(status);
}
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox