* Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
* Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
-
-/* 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 <ynakam@hitachisoft.jp>
* Added -G option Tito Ragusa (C) 2008 for SUSv3.
*/
+//config:config ID
+//config: bool "id (7 kb)"
+//config: default y
+//config: help
+//config: id displays the current user and group ID names.
+//config:
+//config:config GROUPS
+//config: bool "groups (6.7 kb)"
+//config: default y
+//config: help
+//config: Print the group names associated with current user id.
+
+//applet:IF_GROUPS(APPLET_NOEXEC(groups, id, BB_DIR_USR_BIN, BB_SUID_DROP, groups))
+//applet:IF_ID( APPLET_NOEXEC(id, id, BB_DIR_USR_BIN, BB_SUID_DROP, id ))
+
+//kbuild:lib-$(CONFIG_GROUPS) += id.o
+//kbuild:lib-$(CONFIG_ID) += id.o
+
+/* BB_AUDIT SUSv3 compliant. */
+
+//usage:#define id_trivial_usage
+//usage: "[OPTIONS] [USER]"
+//usage:#define id_full_usage "\n\n"
+//usage: "Print information about USER or the current user\n"
+//usage: IF_SELINUX(
+//usage: "\n -Z Security context"
+//usage: )
+//usage: "\n -u User ID"
+//usage: "\n -g Group ID"
+//usage: "\n -G Supplementary group IDs"
+//usage: "\n -n Print names instead of numbers"
+//usage: "\n -r Print real ID instead of effective ID"
+//usage:
+//usage:#define id_example_usage
+//usage: "$ id\n"
+//usage: "uid=1000(andersen) gid=1000(andersen)\n"
+
+//usage:#define groups_trivial_usage
+//usage: "[USER]"
+//usage:#define groups_full_usage "\n\n"
+//usage: "Print the group memberships of USER or for the current process"
+//usage:
+//usage:#define groups_example_usage
+//usage: "$ groups\n"
+//usage: "andersen lp dialout cdrom floppy\n"
#include "libbb.h"
+/* This is a NOEXEC applet. Be very careful! */
+
#if !ENABLE_USE_BB_PWD_GRP
-#if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0)
-#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30)
+#if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 30)
#error "Sorry, you need at least uClibc version 0.9.30 for id applet to build"
#endif
#endif
-#endif
enum {
PRINT_REAL = (1 << 0),
/* On error set *n < 0 and return >= 0
* If *n is too small, update it and return < 0
- * (ok to trash groups[] in both cases)
+ * (ok to trash groups[] in both cases)
* Otherwise fill in groups[] and return >= 0
*/
static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n)
m = getgrouplist(username, rgid, groups, n);
/* I guess *n < 0 might indicate error. Anyway,
* malloc'ing -1 bytes won't be good, so: */
- //if (*n < 0)
- // return 0;
- //return m;
- //commented out here, happens below anyway
- } else {
- /* On error -1 is returned, which ends up in *n */
- int nn = getgroups(*n, groups);
- /* 0: nn <= *n, groups[] was big enough; -1 otherwise */
- m = - (nn > *n);
- *n = nn;
+ if (*n < 0)
+ return 0;
+ return m;
}
- if (*n < 0)
- return 0; /* error, don't return < 0! */
- return m;
+
+ *n = getgroups(*n, groups);
+ if (*n >= 0)
+ return *n;
+ /* Error */
+ if (errno == EINVAL) /* *n is too small? */
+ *n = getgroups(0, groups); /* get needed *n */
+ /* if *n >= 0, return -1 (got new *n), else return 0 (error): */
+ return -(*n >= 0);
}
int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
#if ENABLE_SELINUX
security_context_t scontext = NULL;
#endif
- /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/
- /* 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"
- IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G");
- opt = getopt32(argv, "rnugG" IF_SELINUX("Z"));
+
+ if (ENABLE_GROUPS && (!ENABLE_ID || applet_name[0] == 'g')) {
+ /* TODO: coreutils groups prepend "USER : " prefix,
+ * and accept many usernames. Example:
+ * # groups root root
+ * root : root
+ * root : root
+ */
+ opt = option_mask32 = getopt32(argv, "") | JUST_ALL_GROUPS | NAME_NOT_NUMBER;
+ } else {
+ /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/
+ /* Don't allow more than one username */
+ opt = getopt32(argv, "^"
+ "rnugG" IF_SELINUX("Z")
+ "\0"
+ "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG"
+ IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G")
+ );
+ }
username = argv[optind];
if (username) {
/* We are supplying largish buffer, trying
* to not run get_groups() twice. That might be slow
* ("user database in remote SQL server" case) */
- groups = xmalloc(64 * sizeof(gid_t));
+ groups = xmalloc(64 * sizeof(groups[0]));
n = 64;
if (get_groups(username, rgid, groups, &n) < 0) {
/* Need bigger buffer after all */
- groups = xrealloc(groups, n * sizeof(gid_t));
+ groups = xrealloc(groups, n * sizeof(groups[0]));
get_groups(username, rgid, groups, &n);
}
if (n > 0) {
prefix = ",";
}
} else if (n < 0) { /* error in get_groups() */
- if (!ENABLE_DESKTOP)
- bb_error_msg_and_die("cannot get groups");
- else
- return EXIT_FAILURE;
+ if (ENABLE_DESKTOP)
+ bb_simple_error_msg_and_die("can't get groups");
+ return EXIT_FAILURE;
}
if (ENABLE_FEATURE_CLEAN_UP)
free(groups);