blob: cc4c04ec30066b2d775f29f8b3878ae67c36074c [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 */
28#include <grp.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <pwd.h>
32#include <netdb.h>
33#include <mntent.h>
34#include <private/android_filesystem_config.h>
35#include <pthread.h>
36#include <stdlib.h>
37#include <errno.h>
38#include <ctype.h>
39
Brian Carlstrom1f8e2672011-05-27 00:52:21 -070040static int do_getpw_r(int by_name, const char* name, uid_t uid,
41 struct passwd* dst, char* buf, size_t byte_count, struct passwd** result)
42{
43 /*
44 * getpwnam_r and getpwuid_r don't modify errno, but library calls we
45 * make might.
46 */
47 int old_errno = errno;
48 int rc = 0;
49 *result = NULL;
50
51 const struct passwd* src = by_name ? getpwnam(name) : getpwuid(uid);
52
53 /*
54 * POSIX allows failure to find a match to be considered a non-error.
55 * Reporting success (0) but with *result NULL is glibc's behavior.
56 */
57 if (src == NULL) {
58 rc = (errno == ENOENT) ? 0 : errno;
59 goto failure;
60 }
61
62 /*
63 * Work out where our strings will go in 'buf', and whether we've got
64 * enough space.
65 */
66 size_t required_byte_count = 0;
67 dst->pw_name = buf;
68 required_byte_count += strlen(src->pw_name) + 1;
69 dst->pw_dir = buf + required_byte_count;
70 required_byte_count += strlen(src->pw_dir) + 1;
71 dst->pw_shell = buf + required_byte_count;
72 required_byte_count += strlen(src->pw_shell) + 1;
73 if (byte_count < required_byte_count) {
74 rc = ERANGE;
75 goto failure;
76 }
77
78 /* Copy the strings. */
79 snprintf(buf, byte_count, "%s%c%s%c%s",
80 src->pw_name, 0, src->pw_dir, 0, src->pw_shell);
81
82 /*
83 * pw_passwd is non-POSIX and unused (always NULL) in bionic.
84 * pw_gecos is non-POSIX and missing in bionic.
85 */
86 dst->pw_passwd = NULL;
87
88 /* Copy the integral fields. */
89 dst->pw_gid = src->pw_gid;
90 dst->pw_uid = src->pw_uid;
91
92success:
93 rc = 0;
94 *result = dst;
95failure:
96 errno = old_errno;
97 return rc;
98}
99
100int getpwnam_r(const char* name, struct passwd* pwd,
101 char* buf, size_t byte_count, struct passwd** result)
102{
103 return do_getpw_r(1, name, -1, pwd, buf, byte_count, result);
104}
105
106int getpwuid_r(uid_t uid, struct passwd* pwd,
107 char* buf, size_t byte_count, struct passwd** result)
108{
109 return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
110}
111
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800112/** Thread-specific state for the stubs functions
113 **/
114
Jim Huangc9409452010-10-15 02:21:14 +0800115static pthread_once_t the_once = PTHREAD_ONCE_INIT;
116static pthread_key_t the_key;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800117
118typedef struct {
119 struct passwd passwd;
120 struct group group;
121 char* group_members[2];
122 char app_name_buffer[32];
123 char group_name_buffer[32];
124} stubs_state_t;
125
126static void
127stubs_state_free( void* _s )
128{
129 stubs_state_t* s = _s;
130 free(s);
131}
132
133static stubs_state_t*
134stubs_state_alloc( void )
135{
136 stubs_state_t* s = calloc(1, sizeof *s);
137
138 if (s != NULL) {
139 s->group.gr_mem = s->group_members;
140 }
141 return s;
142}
143
144static void __stubs_key_init(void)
145{
146 pthread_key_create( &the_key, stubs_state_free );
147}
148
149static stubs_state_t*
150__stubs_state(void)
151{
152 stubs_state_t* s;
153
154 pthread_once(&the_once, __stubs_key_init);
155 s = pthread_getspecific(the_key);
156 if (s == NULL) {
157 s = stubs_state_alloc();
158 if (s == NULL) {
159 errno = ENOMEM; /* just in case */
160 } else {
161 if ( pthread_setspecific(the_key, s) != 0 ) {
162 stubs_state_free(s);
163 errno = ENOMEM;
164 s = NULL;
165 }
166 }
167 }
168 return s;
169}
170
171static struct passwd*
172android_iinfo_to_passwd( struct passwd *pw,
173 struct android_id_info *iinfo )
174{
175 pw->pw_name = (char*)iinfo->name;
176 pw->pw_uid = iinfo->aid;
177 pw->pw_gid = iinfo->aid;
178 pw->pw_dir = "/";
179 pw->pw_shell = "/system/bin/sh";
180 return pw;
181}
182
183static struct group*
184android_iinfo_to_group( struct group *gr,
185 struct android_id_info *iinfo )
186{
187 gr->gr_name = (char*) iinfo->name;
188 gr->gr_gid = iinfo->aid;
189 gr->gr_mem[0] = gr->gr_name;
190 gr->gr_mem[1] = NULL;
191 return gr;
192}
193
194static struct passwd *
195android_id_to_passwd( struct passwd *pw, unsigned id)
196{
197 struct android_id_info *iinfo = android_ids;
198 unsigned n;
199 for (n = 0; n < android_id_count; n++) {
200 if (iinfo[n].aid == id) {
201 return android_iinfo_to_passwd(pw, iinfo + n);
202 }
203 }
204 return NULL;
205}
206
207static struct passwd*
208android_name_to_passwd(struct passwd *pw, const char *name)
209{
210 struct android_id_info *iinfo = android_ids;
211 unsigned n;
212 for (n = 0; n < android_id_count; n++) {
213 if (!strcmp(iinfo[n].name, name)) {
214 return android_iinfo_to_passwd(pw, iinfo + n);
215 }
216 }
217 return NULL;
218}
219
220static struct group*
221android_id_to_group( struct group *gr, unsigned id )
222{
223 struct android_id_info *iinfo = android_ids;
224 unsigned n;
225 for (n = 0; n < android_id_count; n++) {
226 if (iinfo[n].aid == id) {
227 return android_iinfo_to_group(gr, iinfo + n);
228 }
229 }
230 return NULL;
231}
232
233static struct group*
234android_name_to_group( struct group *gr, const char *name )
235{
236 struct android_id_info *iinfo = android_ids;
237 unsigned n;
238 for (n = 0; n < android_id_count; n++) {
239 if (!strcmp(iinfo[n].name, name)) {
240 return android_iinfo_to_group(gr, iinfo + n);
241 }
242 }
243 return NULL;
244}
245
246/* translate a user/group name like app_1234 into the
247 * corresponding user/group id (AID_APP + 1234)
248 * returns 0 and sets errno to ENOENT in case of error
249 */
250static unsigned
251app_id_from_name( const char* name )
252{
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800253 unsigned long userid;
254 unsigned long appid;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800255 char* end;
256
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800257 if (name[0] != 'u' || !isdigit(name[1]))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800258 goto FAIL;
259
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800260 userid = strtoul(name+1, &end, 10);
261 if (end[0] != '_' || end[1] == 0 || !isdigit(end[2]))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800262 goto FAIL;
263
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800264 if (end[1] == 'a')
265 appid = strtoul(end+2, &end, 10) + AID_APP;
266 else if (end[1] == 'i')
267 appid = strtoul(end+2, &end, 10) + AID_ISOLATED_START;
268 else
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269 goto FAIL;
270
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800271 if (end[0] != 0)
272 goto FAIL;
273
274 /* check that user id won't overflow */
275 if (userid > 1000)
276 goto FAIL;
277
278 /* check that app id is within range */
279 if (appid < AID_APP || appid >= AID_USER)
280 goto FAIL;
281
282 return (unsigned)(appid + userid*AID_USER);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800283
284FAIL:
285 errno = ENOENT;
286 return 0;
287}
288
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800289static void
290print_app_uid_name(uid_t uid, char* buffer, int bufferlen)
291{
292 uid_t appid;
293 uid_t userid;
294
295 appid = uid % AID_USER;
296 userid = uid / AID_USER;
297
298 if (appid < AID_ISOLATED_START) {
299 snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP);
300 } else {
301 snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
302 }
303}
304
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800305/* translate a uid into the corresponding app_<uid>
306 * passwd structure (sets errno to ENOENT on failure)
307 */
308static struct passwd*
309app_id_to_passwd(uid_t uid, stubs_state_t* state)
310{
311 struct passwd* pw = &state->passwd;
312
313 if (uid < AID_APP) {
314 errno = ENOENT;
315 return NULL;
316 }
317
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800318 print_app_uid_name(uid, state->app_name_buffer, sizeof state->app_name_buffer);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800319
320 pw->pw_name = state->app_name_buffer;
321 pw->pw_dir = "/data";
322 pw->pw_shell = "/system/bin/sh";
323 pw->pw_uid = uid;
324 pw->pw_gid = uid;
325
326 return pw;
327}
328
329/* translate a gid into the corresponding app_<gid>
330 * group structure (sets errno to ENOENT on failure)
331 */
332static struct group*
333app_id_to_group(gid_t gid, stubs_state_t* state)
334{
335 struct group* gr = &state->group;
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800336 int appid;
337 int userid;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800338
339 if (gid < AID_APP) {
340 errno = ENOENT;
341 return NULL;
342 }
343
Dianne Hackborn058d6d82012-02-09 16:14:28 -0800344 print_app_uid_name(gid, state->group_name_buffer, sizeof state->group_name_buffer);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800345
346 gr->gr_name = state->group_name_buffer;
347 gr->gr_gid = gid;
348 gr->gr_mem[0] = gr->gr_name;
349 gr->gr_mem[1] = NULL;
350
351 return gr;
352}
353
354
355struct passwd*
356getpwuid(uid_t uid)
357{
358 stubs_state_t* state = __stubs_state();
359 struct passwd* pw;
360
361 if (state == NULL)
362 return NULL;
363
364 pw = &state->passwd;
365
366 if ( android_id_to_passwd(pw, uid) != NULL )
367 return pw;
368
369 return app_id_to_passwd(uid, state);
370}
371
372struct passwd*
373getpwnam(const char *login)
374{
375 stubs_state_t* state = __stubs_state();
376
377 if (state == NULL)
378 return NULL;
379
380 if (android_name_to_passwd(&state->passwd, login) != NULL)
381 return &state->passwd;
382
383 return app_id_to_passwd( app_id_from_name(login), state );
384}
385
386int
387getgrouplist (const char *user, gid_t group,
388 gid_t *groups, int *ngroups)
389{
390 if (*ngroups < 1) {
391 *ngroups = 1;
392 return -1;
393 }
394 groups[0] = group;
395 return (*ngroups = 1);
396}
397
398char*
399getlogin(void)
400{
401 struct passwd *pw = getpwuid(getuid());
402
403 if(pw) {
404 return pw->pw_name;
405 } else {
406 return NULL;
407 }
408}
409
410struct group*
411getgrgid(gid_t gid)
412{
413 stubs_state_t* state = __stubs_state();
414 struct group* gr;
415
416 if (state == NULL)
417 return NULL;
418
419 gr = android_id_to_group(&state->group, gid);
420 if (gr != NULL)
421 return gr;
422
423 return app_id_to_group(gid, state);
424}
425
426struct group*
427getgrnam(const char *name)
428{
429 stubs_state_t* state = __stubs_state();
430 unsigned id;
431
432 if (state == NULL)
433 return NULL;
434
435 if (android_name_to_group(&state->group, name) != 0)
436 return &state->group;
437
438 return app_id_to_group( app_id_from_name(name), state );
439}
440
441
442struct netent* getnetbyname(const char *name)
443{
444 fprintf(stderr, "FIX ME! implement getgrnam() %s:%d\n", __FILE__, __LINE__);
445 return NULL;
446}
447
448void endpwent(void)
449{
450}
451
452struct mntent* getmntent(FILE* f)
453{
454 fprintf(stderr, "FIX ME! implement getmntent() %s:%d\n", __FILE__, __LINE__);
455 return NULL;
456}
457
458char* ttyname(int fd)
459{
460 fprintf(stderr, "FIX ME! implement ttyname() %s:%d\n", __FILE__, __LINE__);
461 return NULL;
462}
463
Colin Crossfc10b242010-01-13 17:48:34 -0800464int ttyname_r(int fd, char *buf, size_t buflen)
465{
466 fprintf(stderr, "FIX ME! implement ttyname_r() %s:%d\n", __FILE__, __LINE__);
467 return -ERANGE;
468}
469
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800470struct netent *getnetbyaddr(uint32_t net, int type)
471{
472 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
473 return NULL;
474}
475
476struct protoent *getprotobyname(const char *name)
477{
478 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
479 return NULL;
480}
481
482struct protoent *getprotobynumber(int proto)
483{
484 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
485 return NULL;
486}
Colin Crossfc10b242010-01-13 17:48:34 -0800487
488char* getusershell(void)
489{
490 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
491 return NULL;
492}
493
494void setusershell(void)
495{
496 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
497}
498
499void endusershell(void)
500{
501 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
502}