blob: 1aeb58197da247fc363ad9ea6208a514e6931bc1 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
Elliott Hughes52d62332012-07-27 17:40:29 -070028
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080029#include <ctype.h>
Elliott Hughes52d62332012-07-27 17:40:29 -070030#include <errno.h>
31#include <grp.h>
32#include <mntent.h>
33#include <netdb.h>
34#include <private/android_filesystem_config.h>
35#include <private/logd.h>
36#include <pthread.h>
37#include <pwd.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080041
Brian Carlstrom1f8e2672011-05-27 00:52:21 -070042static int do_getpw_r(int by_name, const char* name, uid_t uid,
43 struct passwd* dst, char* buf, size_t byte_count, struct passwd** result)
44{
45 /*
46 * getpwnam_r and getpwuid_r don't modify errno, but library calls we
47 * make might.
48 */
49 int old_errno = errno;
50 int rc = 0;
51 *result = NULL;
52
53 const struct passwd* src = by_name ? getpwnam(name) : getpwuid(uid);
54
55 /*
56 * POSIX allows failure to find a match to be considered a non-error.
57 * Reporting success (0) but with *result NULL is glibc's behavior.
58 */
59 if (src == NULL) {
60 rc = (errno == ENOENT) ? 0 : errno;
61 goto failure;
62 }
63
64 /*
65 * Work out where our strings will go in 'buf', and whether we've got
66 * enough space.
67 */
68 size_t required_byte_count = 0;
69 dst->pw_name = buf;
70 required_byte_count += strlen(src->pw_name) + 1;
71 dst->pw_dir = buf + required_byte_count;
72 required_byte_count += strlen(src->pw_dir) + 1;
73 dst->pw_shell = buf + required_byte_count;
74 required_byte_count += strlen(src->pw_shell) + 1;
75 if (byte_count < required_byte_count) {
76 rc = ERANGE;
77 goto failure;
78 }
79
80 /* Copy the strings. */
81 snprintf(buf, byte_count, "%s%c%s%c%s",
82 src->pw_name, 0, src->pw_dir, 0, src->pw_shell);
83
84 /*
85 * pw_passwd is non-POSIX and unused (always NULL) in bionic.
86 * pw_gecos is non-POSIX and missing in bionic.
87 */
88 dst->pw_passwd = NULL;
89
90 /* Copy the integral fields. */
91 dst->pw_gid = src->pw_gid;
92 dst->pw_uid = src->pw_uid;
93
94success:
95 rc = 0;
96 *result = dst;
97failure:
98 errno = old_errno;
99 return rc;
100}
101
102int getpwnam_r(const char* name, struct passwd* pwd,
103 char* buf, size_t byte_count, struct passwd** result)
104{
105 return do_getpw_r(1, name, -1, pwd, buf, byte_count, result);
106}
107
108int getpwuid_r(uid_t uid, struct passwd* pwd,
109 char* buf, size_t byte_count, struct passwd** result)
110{
111 return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
112}
113
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800114/** Thread-specific state for the stubs functions
115 **/
116
Jim Huangc9409452010-10-15 02:21:14 +0800117static pthread_once_t the_once = PTHREAD_ONCE_INIT;
118static pthread_key_t the_key;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800119
120typedef struct {
121 struct passwd passwd;
122 struct group group;
123 char* group_members[2];
124 char app_name_buffer[32];
125 char group_name_buffer[32];
126} stubs_state_t;
127
128static void
129stubs_state_free( void* _s )
130{
131 stubs_state_t* s = _s;
132 free(s);
133}
134
135static stubs_state_t*
136stubs_state_alloc( void )
137{
138 stubs_state_t* s = calloc(1, sizeof *s);
139
140 if (s != NULL) {
141 s->group.gr_mem = s->group_members;
142 }
143 return s;
144}
145
146static void __stubs_key_init(void)
147{
148 pthread_key_create( &the_key, stubs_state_free );
149}
150
151static stubs_state_t*
152__stubs_state(void)
153{
154 stubs_state_t* s;
155
156 pthread_once(&the_once, __stubs_key_init);
157 s = pthread_getspecific(the_key);
158 if (s == NULL) {
159 s = stubs_state_alloc();
160 if (s == NULL) {
161 errno = ENOMEM; /* just in case */
162 } else {
163 if ( pthread_setspecific(the_key, s) != 0 ) {
164 stubs_state_free(s);
165 errno = ENOMEM;
166 s = NULL;
167 }
168 }
169 }
170 return s;
171}
172
173static struct passwd*
174android_iinfo_to_passwd( struct passwd *pw,
175 struct android_id_info *iinfo )
176{
177 pw->pw_name = (char*)iinfo->name;
178 pw->pw_uid = iinfo->aid;
179 pw->pw_gid = iinfo->aid;
180 pw->pw_dir = "/";
181 pw->pw_shell = "/system/bin/sh";
182 return pw;
183}
184
185static struct group*
186android_iinfo_to_group( struct group *gr,
187 struct android_id_info *iinfo )
188{
189 gr->gr_name = (char*) iinfo->name;
190 gr->gr_gid = iinfo->aid;
191 gr->gr_mem[0] = gr->gr_name;
192 gr->gr_mem[1] = NULL;
193 return gr;
194}
195
196static struct passwd *
197android_id_to_passwd( struct passwd *pw, unsigned id)
198{
199 struct android_id_info *iinfo = android_ids;
200 unsigned n;
201 for (n = 0; n < android_id_count; n++) {
202 if (iinfo[n].aid == id) {
203 return android_iinfo_to_passwd(pw, iinfo + n);
204 }
205 }
206 return NULL;
207}
208
209static struct passwd*
210android_name_to_passwd(struct passwd *pw, const char *name)
211{
212 struct android_id_info *iinfo = android_ids;
213 unsigned n;
214 for (n = 0; n < android_id_count; n++) {
215 if (!strcmp(iinfo[n].name, name)) {
216 return android_iinfo_to_passwd(pw, iinfo + n);
217 }
218 }
219 return NULL;
220}
221
222static struct group*
223android_id_to_group( struct group *gr, unsigned id )
224{
225 struct android_id_info *iinfo = android_ids;
226 unsigned n;
227 for (n = 0; n < android_id_count; n++) {
228 if (iinfo[n].aid == id) {
229 return android_iinfo_to_group(gr, iinfo + n);
230 }
231 }
232 return NULL;
233}
234
235static struct group*
236android_name_to_group( struct group *gr, const char *name )
237{
238 struct android_id_info *iinfo = android_ids;
239 unsigned n;
240 for (n = 0; n < android_id_count; n++) {
241 if (!strcmp(iinfo[n].name, name)) {
242 return android_iinfo_to_group(gr, iinfo + n);
243 }
244 }
245 return NULL;
246}
247
248/* translate a user/group name like app_1234 into the
249 * corresponding user/group id (AID_APP + 1234)
250 * returns 0 and sets errno to ENOENT in case of error
251 */
252static unsigned
253app_id_from_name( const char* name )
254{
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800255 unsigned long userid;
256 unsigned long appid;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800257 char* end;
258
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800259 if (name[0] != 'u' || !isdigit(name[1]))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800260 goto FAIL;
261
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800262 userid = strtoul(name+1, &end, 10);
263 if (end[0] != '_' || end[1] == 0 || !isdigit(end[2]))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800264 goto FAIL;
265
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800266 if (end[1] == 'a')
267 appid = strtoul(end+2, &end, 10) + AID_APP;
268 else if (end[1] == 'i')
269 appid = strtoul(end+2, &end, 10) + AID_ISOLATED_START;
270 else
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800271 goto FAIL;
272
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800273 if (end[0] != 0)
274 goto FAIL;
275
276 /* check that user id won't overflow */
277 if (userid > 1000)
278 goto FAIL;
279
280 /* check that app id is within range */
281 if (appid < AID_APP || appid >= AID_USER)
282 goto FAIL;
283
284 return (unsigned)(appid + userid*AID_USER);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800285
286FAIL:
287 errno = ENOENT;
288 return 0;
289}
290
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800291static void
292print_app_uid_name(uid_t uid, char* buffer, int bufferlen)
293{
294 uid_t appid;
295 uid_t userid;
296
297 appid = uid % AID_USER;
298 userid = uid / AID_USER;
299
300 if (appid < AID_ISOLATED_START) {
301 snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);
302 } else {
303 snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
304 }
305}
306
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800307/* translate a uid into the corresponding app_<uid>
308 * passwd structure (sets errno to ENOENT on failure)
309 */
310static struct passwd*
311app_id_to_passwd(uid_t uid, stubs_state_t* state)
312{
313 struct passwd* pw = &state->passwd;
314
315 if (uid < AID_APP) {
316 errno = ENOENT;
317 return NULL;
318 }
319
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800320 print_app_uid_name(uid, state->app_name_buffer, sizeof state->app_name_buffer);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800321
322 pw->pw_name = state->app_name_buffer;
323 pw->pw_dir = "/data";
324 pw->pw_shell = "/system/bin/sh";
325 pw->pw_uid = uid;
326 pw->pw_gid = uid;
327
328 return pw;
329}
330
331/* translate a gid into the corresponding app_<gid>
332 * group structure (sets errno to ENOENT on failure)
333 */
334static struct group*
335app_id_to_group(gid_t gid, stubs_state_t* state)
336{
337 struct group* gr = &state->group;
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800338 int appid;
339 int userid;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800340
341 if (gid < AID_APP) {
342 errno = ENOENT;
343 return NULL;
344 }
345
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800346 print_app_uid_name(gid, state->group_name_buffer, sizeof state->group_name_buffer);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800347
348 gr->gr_name = state->group_name_buffer;
349 gr->gr_gid = gid;
350 gr->gr_mem[0] = gr->gr_name;
351 gr->gr_mem[1] = NULL;
352
353 return gr;
354}
355
356
357struct passwd*
358getpwuid(uid_t uid)
359{
360 stubs_state_t* state = __stubs_state();
361 struct passwd* pw;
362
363 if (state == NULL)
364 return NULL;
365
366 pw = &state->passwd;
367
368 if ( android_id_to_passwd(pw, uid) != NULL )
369 return pw;
370
371 return app_id_to_passwd(uid, state);
372}
373
374struct passwd*
375getpwnam(const char *login)
376{
377 stubs_state_t* state = __stubs_state();
378
379 if (state == NULL)
380 return NULL;
381
382 if (android_name_to_passwd(&state->passwd, login) != NULL)
383 return &state->passwd;
384
385 return app_id_to_passwd( app_id_from_name(login), state );
386}
387
388int
389getgrouplist (const char *user, gid_t group,
390 gid_t *groups, int *ngroups)
391{
392 if (*ngroups < 1) {
393 *ngroups = 1;
394 return -1;
395 }
396 groups[0] = group;
397 return (*ngroups = 1);
398}
399
400char*
401getlogin(void)
402{
403 struct passwd *pw = getpwuid(getuid());
404
405 if(pw) {
406 return pw->pw_name;
407 } else {
408 return NULL;
409 }
410}
411
412struct group*
413getgrgid(gid_t gid)
414{
415 stubs_state_t* state = __stubs_state();
416 struct group* gr;
417
418 if (state == NULL)
419 return NULL;
420
421 gr = android_id_to_group(&state->group, gid);
422 if (gr != NULL)
423 return gr;
424
425 return app_id_to_group(gid, state);
426}
427
428struct group*
429getgrnam(const char *name)
430{
431 stubs_state_t* state = __stubs_state();
432 unsigned id;
433
434 if (state == NULL)
435 return NULL;
436
437 if (android_name_to_group(&state->group, name) != 0)
438 return &state->group;
439
440 return app_id_to_group( app_id_from_name(name), state );
441}
442
Elliott Hughes52d62332012-07-27 17:40:29 -0700443static void unimplemented_stub(const char* function) {
444 const char* fmt = "%s(3) is not implemented on Android\n";
445 __libc_android_log_print(ANDROID_LOG_WARN, "libc", fmt, function);
446 fprintf(stderr, fmt, function);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800447}
448
Elliott Hughes52d62332012-07-27 17:40:29 -0700449#define UNIMPLEMENTED unimplemented_stub(__PRETTY_FUNCTION__)
450
451struct netent* getnetbyname(const char* name) {
452 UNIMPLEMENTED;
453 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800454}
455
Elliott Hughes52d62332012-07-27 17:40:29 -0700456void endpwent(void) {
457 UNIMPLEMENTED;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800458}
459
Elliott Hughes52d62332012-07-27 17:40:29 -0700460struct mntent* getmntent(FILE* f) {
461 UNIMPLEMENTED;
462 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800463}
464
Elliott Hughes52d62332012-07-27 17:40:29 -0700465char* ttyname(int fd) {
466 UNIMPLEMENTED;
467 return NULL;
Colin Crossfc10b242010-01-13 17:48:34 -0800468}
469
Elliott Hughes52d62332012-07-27 17:40:29 -0700470int ttyname_r(int fd, char* buf, size_t buflen) {
471 UNIMPLEMENTED;
472 return -ERANGE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800473}
474
Elliott Hughes52d62332012-07-27 17:40:29 -0700475struct netent* getnetbyaddr(uint32_t net, int type) {
476 UNIMPLEMENTED;
477 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800478}
479
Elliott Hughes52d62332012-07-27 17:40:29 -0700480struct protoent* getprotobyname(const char* name) {
481 UNIMPLEMENTED;
482 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800483}
Colin Crossfc10b242010-01-13 17:48:34 -0800484
Elliott Hughes52d62332012-07-27 17:40:29 -0700485struct protoent* getprotobynumber(int proto) {
486 UNIMPLEMENTED;
487 return NULL;
Colin Crossfc10b242010-01-13 17:48:34 -0800488}
489
Elliott Hughes52d62332012-07-27 17:40:29 -0700490char* getusershell(void) {
491 UNIMPLEMENTED;
492 return NULL;
Colin Crossfc10b242010-01-13 17:48:34 -0800493}
494
Elliott Hughes52d62332012-07-27 17:40:29 -0700495void setusershell(void) {
496 UNIMPLEMENTED;
497}
498
499void endusershell(void) {
500 UNIMPLEMENTED;
Colin Crossfc10b242010-01-13 17:48:34 -0800501}