source: MondoRescue/branches/3.3/mindi-busybox/coreutils/id.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 7.2 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini id implementation for busybox
4 *
5 * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
6 * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
10
11/* BB_AUDIT SUSv3 compliant. */
12/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever
13 * length and to be more similar to GNU id.
14 * -Z option support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
15 * Added -G option Tito Ragusa (C) 2008 for SUSv3.
16 */
17
18//config:config ID
19//config: bool "id"
20//config: default y
21//config: help
22//config: id displays the current user and group ID names.
23
24//config:config GROUPS
25//config: bool "groups"
26//config: default y
27//config: help
28//config: Print the group names associated with current user id.
29
30//kbuild:lib-$(CONFIG_GROUPS) += id.o
31//kbuild:lib-$(CONFIG_ID) += id.o
32
33//applet:IF_GROUPS(APPLET_NOEXEC(groups, id, BB_DIR_USR_BIN, BB_SUID_DROP, groups))
34//applet:IF_ID( APPLET_NOEXEC(id, id, BB_DIR_USR_BIN, BB_SUID_DROP, id ))
35
36//usage:#define id_trivial_usage
37//usage: "[OPTIONS] [USER]"
38//usage:#define id_full_usage "\n\n"
39//usage: "Print information about USER or the current user\n"
40//usage: IF_SELINUX(
41//usage: "\n -Z Security context"
42//usage: )
43//usage: "\n -u User ID"
44//usage: "\n -g Group ID"
45//usage: "\n -G Supplementary group IDs"
46//usage: "\n -n Print names instead of numbers"
47//usage: "\n -r Print real ID instead of effective ID"
48//usage:
49//usage:#define id_example_usage
50//usage: "$ id\n"
51//usage: "uid=1000(andersen) gid=1000(andersen)\n"
52
53//usage:#define groups_trivial_usage
54//usage: "[USER]"
55//usage:#define groups_full_usage "\n\n"
56//usage: "Print the group memberships of USER or for the current process"
57//usage:
58//usage:#define groups_example_usage
59//usage: "$ groups\n"
60//usage: "andersen lp dialout cdrom floppy\n"
61
62#include "libbb.h"
63
64/* This is a NOEXEC applet. Be very careful! */
65
66#if !ENABLE_USE_BB_PWD_GRP
67#if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 30)
68#error "Sorry, you need at least uClibc version 0.9.30 for id applet to build"
69#endif
70#endif
71
72enum {
73 PRINT_REAL = (1 << 0),
74 NAME_NOT_NUMBER = (1 << 1),
75 JUST_USER = (1 << 2),
76 JUST_GROUP = (1 << 3),
77 JUST_ALL_GROUPS = (1 << 4),
78#if ENABLE_SELINUX
79 JUST_CONTEXT = (1 << 5),
80#endif
81};
82
83static int print_common(unsigned id, const char *name, const char *prefix)
84{
85 if (prefix) {
86 printf("%s", prefix);
87 }
88 if (!(option_mask32 & NAME_NOT_NUMBER) || !name) {
89 printf("%u", id);
90 }
91 if (!option_mask32 || (option_mask32 & NAME_NOT_NUMBER)) {
92 if (name) {
93 printf(option_mask32 ? "%s" : "(%s)", name);
94 } else {
95 /* Don't set error status flag in default mode */
96 if (option_mask32) {
97 if (ENABLE_DESKTOP)
98 bb_error_msg("unknown ID %u", id);
99 return EXIT_FAILURE;
100 }
101 }
102 }
103 return EXIT_SUCCESS;
104}
105
106static int print_group(gid_t id, const char *prefix)
107{
108 return print_common(id, gid2group(id), prefix);
109}
110
111static int print_user(uid_t id, const char *prefix)
112{
113 return print_common(id, uid2uname(id), prefix);
114}
115
116/* On error set *n < 0 and return >= 0
117 * If *n is too small, update it and return < 0
118 * (ok to trash groups[] in both cases)
119 * Otherwise fill in groups[] and return >= 0
120 */
121static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n)
122{
123 int m;
124
125 if (username) {
126 /* If the user is a member of more than
127 * *n groups, then -1 is returned. Otherwise >= 0.
128 * (and no defined way of detecting errors?!) */
129 m = getgrouplist(username, rgid, groups, n);
130 /* I guess *n < 0 might indicate error. Anyway,
131 * malloc'ing -1 bytes won't be good, so: */
132 if (*n < 0)
133 return 0;
134 return m;
135 }
136
137 *n = getgroups(*n, groups);
138 if (*n >= 0)
139 return *n;
140 /* Error */
141 if (errno == EINVAL) /* *n is too small? */
142 *n = getgroups(0, groups); /* get needed *n */
143 /* if *n >= 0, return -1 (got new *n), else return 0 (error): */
144 return -(*n >= 0);
145}
146
147int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
148int id_main(int argc UNUSED_PARAM, char **argv)
149{
150 uid_t ruid;
151 gid_t rgid;
152 uid_t euid;
153 gid_t egid;
154 unsigned opt;
155 int i;
156 int status = EXIT_SUCCESS;
157 const char *prefix;
158 const char *username;
159#if ENABLE_SELINUX
160 security_context_t scontext = NULL;
161#endif
162
163 if (ENABLE_GROUPS && (!ENABLE_ID || applet_name[0] == 'g')) {
164 /* TODO: coreutils groups prepend "USER : " prefix,
165 * and accept many usernames. Example:
166 * # groups root root
167 * root : root
168 * root : root
169 */
170 opt = option_mask32 = getopt32(argv, "") | JUST_ALL_GROUPS | NAME_NOT_NUMBER;
171 } else {
172 /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/
173 /* Don't allow more than one username */
174 opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG"
175 IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G");
176 opt = getopt32(argv, "rnugG" IF_SELINUX("Z"));
177 }
178
179 username = argv[optind];
180 if (username) {
181 struct passwd *p = xgetpwnam(username);
182 euid = ruid = p->pw_uid;
183 egid = rgid = p->pw_gid;
184 } else {
185 egid = getegid();
186 rgid = getgid();
187 euid = geteuid();
188 ruid = getuid();
189 }
190 /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */
191 /* id says: print the real ID instead of the effective ID, with -ugG */
192 /* in fact in this case egid is always printed if egid != rgid */
193 if (!opt || (opt & JUST_ALL_GROUPS)) {
194 gid_t *groups;
195 int n;
196
197 if (!opt) {
198 /* Default Mode */
199 status |= print_user(ruid, "uid=");
200 status |= print_group(rgid, " gid=");
201 if (euid != ruid)
202 status |= print_user(euid, " euid=");
203 if (egid != rgid)
204 status |= print_group(egid, " egid=");
205 } else {
206 /* JUST_ALL_GROUPS */
207 status |= print_group(rgid, NULL);
208 if (egid != rgid)
209 status |= print_group(egid, " ");
210 }
211 /* We are supplying largish buffer, trying
212 * to not run get_groups() twice. That might be slow
213 * ("user database in remote SQL server" case) */
214 groups = xmalloc(64 * sizeof(groups[0]));
215 n = 64;
216 if (get_groups(username, rgid, groups, &n) < 0) {
217 /* Need bigger buffer after all */
218 groups = xrealloc(groups, n * sizeof(groups[0]));
219 get_groups(username, rgid, groups, &n);
220 }
221 if (n > 0) {
222 /* Print the list */
223 prefix = " groups=";
224 for (i = 0; i < n; i++) {
225 if (opt && (groups[i] == rgid || groups[i] == egid))
226 continue;
227 status |= print_group(groups[i], opt ? " " : prefix);
228 prefix = ",";
229 }
230 } else if (n < 0) { /* error in get_groups() */
231 if (ENABLE_DESKTOP)
232 bb_error_msg_and_die("can't get groups");
233 return EXIT_FAILURE;
234 }
235 if (ENABLE_FEATURE_CLEAN_UP)
236 free(groups);
237#if ENABLE_SELINUX
238 if (is_selinux_enabled()) {
239 if (getcon(&scontext) == 0)
240 printf(" context=%s", scontext);
241 }
242#endif
243 } else if (opt & PRINT_REAL) {
244 euid = ruid;
245 egid = rgid;
246 }
247
248 if (opt & JUST_USER)
249 status |= print_user(euid, NULL);
250 else if (opt & JUST_GROUP)
251 status |= print_group(egid, NULL);
252#if ENABLE_SELINUX
253 else if (opt & JUST_CONTEXT) {
254 selinux_or_die();
255 if (username || getcon(&scontext)) {
256 bb_error_msg_and_die("can't get process context%s",
257 username ? " for a different user" : "");
258 }
259 fputs(scontext, stdout);
260 }
261 /* freecon(NULL) seems to be harmless */
262 if (ENABLE_FEATURE_CLEAN_UP)
263 freecon(scontext);
264#endif
265 bb_putchar('\n');
266 fflush_stdout_and_exit(status);
267}
Note: See TracBrowser for help on using the repository browser.