diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-29 00:27:31 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-29 00:27:31 +0000 |
commit | 34e68c8b42ccbc8b04e6184f4985c3b47e6c6df0 (patch) | |
tree | 561bfdec1b2633b25d10e1a8044de3c7184b334c /coreutils/id.c | |
parent | d498850e02861ac4422f9a1e88deb8dec2c34887 (diff) | |
download | busybox-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.c | 290 |
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 | 20 | enum { |
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 | ||
28 | static int printf_full(unsigned id, const char *arg, const char *prefix) | 31 | static 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__)) | 58 | static 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 | 63 | static 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 | */ | ||
73 | static 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 | ||
49 | int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 100 | int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
50 | int id_main(int argc UNUSED_PARAM, char **argv) | 101 | int 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 | } |