aboutsummaryrefslogtreecommitdiff
path: root/coreutils/id.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-29 00:27:31 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-29 00:27:31 +0000
commit34e68c8b42ccbc8b04e6184f4985c3b47e6c6df0 (patch)
tree561bfdec1b2633b25d10e1a8044de3c7184b334c /coreutils/id.c
parentd498850e02861ac4422f9a1e88deb8dec2c34887 (diff)
downloadbusybox-w32-34e68c8b42ccbc8b04e6184f4985c3b47e6c6df0.tar.gz
busybox-w32-34e68c8b42ccbc8b04e6184f4985c3b47e6c6df0.tar.bz2
busybox-w32-34e68c8b42ccbc8b04e6184f4985c3b47e6c6df0.zip
id: coreutils compat by Tito + test script
Diffstat (limited to 'coreutils/id.c')
-rw-r--r--coreutils/id.c290
1 files changed, 162 insertions, 128 deletions
diff --git a/coreutils/id.c b/coreutils/id.c
index aa27ed394..b00532f83 100644
--- a/coreutils/id.c
+++ b/coreutils/id.c
@@ -3,176 +3,210 @@
3 * Mini id implementation for busybox 3 * Mini id implementation for busybox
4 * 4 *
5 * Copyright (C) 2000 by Randolph Chung <tausq@debian.org> 5 * Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
6 * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
6 * 7 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */ 9 */
9 10
10/* BB_AUDIT SUSv3 compliant. */ 11/* BB_AUDIT SUSv3 compliant. */
11/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever length and to 12/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever
12 * be more similar to GNU id. 13 * length and to be more similar to GNU id.
13 * -Z option support: by Yuichi Nakamura <ynakam@hitachisoft.jp> 14 * -Z option support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
14 * Added -G option Tito Ragusa (C) 2008 for SUSv3. 15 * Added -G option Tito Ragusa (C) 2008 for SUSv3.
15 */ 16 */
16 17
17#include "libbb.h" 18#include "libbb.h"
18 19
19#define PRINT_REAL 1 20enum {
20#define NAME_NOT_NUMBER 2 21 PRINT_REAL = (1 << 0),
21#define JUST_USER 4 22 NAME_NOT_NUMBER = (1 << 1),
22#define JUST_GROUP 8 23 JUST_USER = (1 << 2),
23#define JUST_ALL_GROUPS 16 24 JUST_GROUP = (1 << 3),
25 JUST_ALL_GROUPS = (1 << 4),
24#if ENABLE_SELINUX 26#if ENABLE_SELINUX
25#define JUST_CONTEXT 32 27 JUST_CONTEXT = (1 << 5),
26#endif 28#endif
29};
27 30
28static int printf_full(unsigned id, const char *arg, const char *prefix) 31static int print_common(unsigned id,
32 char* FAST_FUNC bb_getXXXid(char *name, int bufsize, long uid),
33 const char *prefix)
29{ 34{
30 const char *fmt = "%s%u"; 35 const char *name = bb_getXXXid(NULL, 0, id);
31 int status = EXIT_FAILURE;
32 36
33 if (arg) { 37 if (prefix) {
34 fmt = "%s%u(%s)"; 38 printf("%s", prefix);
35 status = EXIT_SUCCESS;
36 } 39 }
37 printf(fmt, prefix, id, arg); 40 if (!(option_mask32 & NAME_NOT_NUMBER) || !name) {
38 return status; 41 printf("%u", id);
42 }
43 if (!option_mask32 || (option_mask32 & NAME_NOT_NUMBER)) {
44 if (name) {
45 printf(option_mask32 ? "%s" : "(%s)", name);
46 } else {
47 /* Don't set error status flag in default mode */
48 if (option_mask32) {
49 if (ENABLE_DESKTOP)
50 bb_error_msg("unknown ID %u", id);
51 return EXIT_FAILURE;
52 }
53 }
54 }
55 return EXIT_SUCCESS;
39} 56}
40 57
41#if (defined(__GLIBC__) && !defined(__UCLIBC__)) 58static int print_group(gid_t id, const char *prefix)
42#define HAVE_getgrouplist 1 59{
43#elif ENABLE_USE_BB_PWD_GRP 60 return print_common(id, bb_getgrgid, prefix);
44#define HAVE_getgrouplist 1 61}
45#else 62
46#define HAVE_getgrouplist 0 63static int print_user(gid_t id, const char *prefix)
47#endif 64{
65 return print_common(id, bb_getpwuid, prefix);
66}
67
68/* On error set *n < 0 and return >= 0
69 * If *n is too small, update it and return < 0
70 * (ok to trash groups[] in both cases)
71 * Otherwise fill in groups[] and return >= 0
72 */
73static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n)
74{
75 int m;
76
77 if (username) {
78 /* If the user is a member of more than
79 * *n groups, then -1 is returned. Otherwise >= 0.
80 * (and no defined way of detecting errors?!) */
81 m = getgrouplist(username, rgid, groups, n);
82 /* I guess *n < 0 might indicate error. Anyway,
83 * malloc'ing -1 bytes won't be good, so: */
84 //if (*n < 0)
85 // return 0;
86 //return m;
87 //commented here, happens below anyway
88 } else {
89 /* On error -1 is returned, which ends up in *n */
90 int nn = getgroups(*n, groups);
91 /* 0: nn <= *n, groups[] was big enough; -1 otherwise */
92 m = - (nn > *n);
93 *n = nn;
94 }
95 if (*n < 0)
96 return 0; /* error, don't return < 0! */
97 return m;
98}
48 99
49int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 100int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int id_main(int argc UNUSED_PARAM, char **argv) 101int id_main(int argc UNUSED_PARAM, char **argv)
51{ 102{
103 uid_t ruid;
104 gid_t rgid;
105 uid_t euid;
106 gid_t egid;
107 unsigned opt;
108 int i;
109 int status = EXIT_SUCCESS;
110 const char *prefix;
52 const char *username; 111 const char *username;
53 struct passwd *p;
54 uid_t uid;
55 gid_t gid;
56#if HAVE_getgrouplist
57 gid_t *groups;
58 int n;
59#endif
60 unsigned flags;
61 short status;
62#if ENABLE_SELINUX 112#if ENABLE_SELINUX
63 security_context_t scontext; 113 security_context_t scontext = NULL;
64#endif 114#endif
65 /* Don't allow -n -r -nr -ug -rug -nug -rnug */ 115 /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/
66 /* Don't allow more than one username */ 116 /* Don't allow more than one username */
67 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"); 117 opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG"
68 flags = getopt32(argv, "rnugG" USE_SELINUX("Z")); 118 USE_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G");
69 username = argv[optind]; 119 opt = getopt32(argv, "rnugG" USE_SELINUX("Z"));
70
71 /* This values could be overwritten later */
72 uid = geteuid();
73 gid = getegid();
74 if (flags & PRINT_REAL) {
75 uid = getuid();
76 gid = getgid();
77 }
78 120
121 username = argv[optind];
79 if (username) { 122 if (username) {
80#if HAVE_getgrouplist 123 struct passwd *p = getpwnam(username);
81 int m; 124 if (!p)
82#endif 125 bb_error_msg_and_die("unknown user %s", username);
83 p = getpwnam(username); 126 euid = ruid = p->pw_uid;
84 /* xuname2uid is needed because it exits on failure */ 127 egid = rgid = p->pw_gid;
85 uid = xuname2uid(username);
86 gid = p->pw_gid; /* in this case PRINT_REAL is the same */
87
88#if HAVE_getgrouplist
89 n = 16;
90 groups = NULL;
91 do {
92 m = n;
93 groups = xrealloc(groups, sizeof(groups[0]) * m);
94 getgrouplist(username, gid, groups, &n); /* GNUism? */
95 } while (n > m);
96#endif
97 } else { 128 } else {
98#if HAVE_getgrouplist 129 egid = getegid();
99 n = getgroups(0, NULL); 130 rgid = getgid();
100 groups = xmalloc(sizeof(groups[0]) * n); 131 euid = geteuid();
101 getgroups(n, groups); 132 ruid = getuid();
102#endif
103 }
104
105 if (flags & JUST_ALL_GROUPS) {
106#if HAVE_getgrouplist
107 while (n--) {
108 if (flags & NAME_NOT_NUMBER)
109 printf("%s", bb_getgrgid(NULL, 0, *groups++));
110 else
111 printf("%u", (unsigned) *groups++);
112 bb_putchar((n > 0) ? ' ' : '\n');
113 }
114#endif
115 /* exit */
116 fflush_stdout_and_exit(EXIT_SUCCESS);
117 } 133 }
118 134 /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */
119 if (flags & (JUST_GROUP | JUST_USER USE_SELINUX(| JUST_CONTEXT))) { 135 /* id says: print the real ID instead of the effective ID, with -ugG */
120 /* JUST_GROUP and JUST_USER are mutually exclusive */ 136 /* in fact in ths case egid is always printed if egid != rgid */
121 if (flags & NAME_NOT_NUMBER) { 137 if (!opt || (opt & JUST_ALL_GROUPS)) {
122 /* bb_getXXXid(-1) exits on failure, puts cannot segfault */ 138 gid_t *groups;
123 puts((flags & JUST_USER) ? bb_getpwuid(NULL, -1, uid) : bb_getgrgid(NULL, -1, gid)); 139 int n;
140
141 if (!opt) {
142 /* Default Mode */
143 status |= print_user(ruid, "uid=");
144 status |= print_group(rgid, " gid=");
145 if (euid != ruid)
146 status |= print_user(euid, " euid=");
147 if (egid != rgid)
148 status |= print_group(egid, " egid=");
124 } else { 149 } else {
125 if (flags & JUST_USER) { 150 /* JUST_ALL_GROUPS */
126 printf("%u\n", (unsigned)uid); 151 status |= print_group(rgid, NULL);
127 } 152 if (egid != rgid)
128 if (flags & JUST_GROUP) { 153 status |= print_group(egid, " ");
129 printf("%u\n", (unsigned)gid); 154 }
155 /* We'd rather try supplying largish buffer than
156 * having get_groups() run twice. That might be slow
157 * (think about "user database in remove SQL server" case) */
158 groups = xmalloc(64 * sizeof(gid_t));
159 n = 64;
160 if (get_groups(username, rgid, groups, &n) < 0) {
161 /* Need bigger buffer after all */
162 groups = xrealloc(groups, n * sizeof(gid_t));
163 get_groups(username, rgid, groups, &n);
164 }
165 if (n > 0) {
166 /* Print the list */
167 prefix = " groups=";
168 for (i = 0; i < n; i++) {
169 if (opt && (groups[i] == rgid || groups[i] == egid))
170 continue;
171 status |= print_group(groups[i], opt ? " " : prefix);
172 prefix = ",";
130 } 173 }
174 if (ENABLE_FEATURE_CLEAN_UP)
175 free(groups);
176 } else if (n < 0) { /* error in get_groups() */
177 if (!ENABLE_DESKTOP)
178 bb_error_msg_and_die("cannot get groups");
179 else
180 return EXIT_FAILURE;
131 } 181 }
132
133#if ENABLE_SELINUX 182#if ENABLE_SELINUX
134 if (flags & JUST_CONTEXT) { 183 if (is_selinux_enabled()) {
135 selinux_or_die(); 184 if (getcon(&scontext) == 0)
136 if (username) { 185 printf(" context=%s", scontext);
137 bb_error_msg_and_die("user name can't be passed with -Z");
138 }
139
140 if (getcon(&scontext)) {
141 bb_error_msg_and_die("can't get process context");
142 }
143 puts(scontext);
144 } 186 }
145#endif 187#endif
146 /* exit */ 188 } else if (opt & PRINT_REAL) {
147 fflush_stdout_and_exit(EXIT_SUCCESS); 189 euid = ruid;
190 egid = rgid;
148 } 191 }
149 192
150 /* Print full info like GNU id */ 193 if (opt & JUST_USER)
151 /* bb_getpwuid(0) doesn't exit on failure (returns NULL) */ 194 status |= print_user(euid, NULL);
152 status = printf_full(uid, bb_getpwuid(NULL, 0, uid), "uid="); 195 else if (opt & JUST_GROUP)
153 status |= printf_full(gid, bb_getgrgid(NULL, 0, gid), " gid="); 196 status |= print_group(egid, NULL);
154#if HAVE_getgrouplist
155 {
156 const char *msg = " groups=";
157 while (n--) {
158 status |= printf_full(*groups, bb_getgrgid(NULL, 0, *groups), msg);
159 msg = ",";
160 groups++;
161 }
162 }
163 /* we leak groups vector... */
164#endif
165
166#if ENABLE_SELINUX 197#if ENABLE_SELINUX
167 if (is_selinux_enabled()) { 198 else if (opt & JUST_CONTEXT) {
168 security_context_t mysid; 199 selinux_or_die();
169 getcon(&mysid); 200 if (username || getcon(&scontext)) {
170 printf(" context=%s", mysid ? mysid : "unknown"); 201 bb_error_msg_and_die("can't get process context%s",
171 if (mysid) /* TODO: maybe freecon(NULL) is harmless? */ 202 username ? " for a different user" : "");
172 freecon(mysid); 203 }
204 fputs(scontext, stdout);
173 } 205 }
206 /* freecon(NULL) seems to be harmless */
207 if (ENABLE_FEATURE_CLEAN_UP)
208 freecon(scontext);
174#endif 209#endif
175
176 bb_putchar('\n'); 210 bb_putchar('\n');
177 fflush_stdout_and_exit(status); 211 fflush_stdout_and_exit(status);
178} 212}