1 /* 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 40 static 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 92 success: 93 rc = 0; 94 *result = dst; 95 failure: 96 errno = old_errno; 97 return rc; 98 } 99 100 int 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 106 int 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 112 /** Thread-specific state for the stubs functions 113 **/ 114 115 static pthread_once_t the_once = PTHREAD_ONCE_INIT; 116 static pthread_key_t the_key; 117 118 typedef 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 126 static void 127 stubs_state_free( void* _s ) 128 { 129 stubs_state_t* s = _s; 130 free(s); 131 } 132 133 static stubs_state_t* 134 stubs_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 144 static void __stubs_key_init(void) 145 { 146 pthread_key_create( &the_key, stubs_state_free ); 147 } 148 149 static 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 171 static struct passwd* 172 android_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 183 static struct group* 184 android_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 194 static struct passwd * 195 android_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 207 static struct passwd* 208 android_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 220 static struct group* 221 android_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 233 static struct group* 234 android_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 */ 250 static unsigned 251 app_id_from_name( const char* name ) 252 { 253 unsigned long userid; 254 unsigned long appid; 255 char* end; 256 257 if (name[0] != 'u' || !isdigit(name[1])) 258 goto FAIL; 259 260 userid = strtoul(name+1, &end, 10); 261 if (end[0] != '_' || end[1] == 0 || !isdigit(end[2])) 262 goto FAIL; 263 264 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 269 goto FAIL; 270 271 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); 283 284 FAIL: 285 errno = ENOENT; 286 return 0; 287 } 288 289 static void 290 print_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 305 /* translate a uid into the corresponding app_<uid> 306 * passwd structure (sets errno to ENOENT on failure) 307 */ 308 static struct passwd* 309 app_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 318 print_app_uid_name(uid, state->app_name_buffer, sizeof state->app_name_buffer); 319 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 */ 332 static struct group* 333 app_id_to_group(gid_t gid, stubs_state_t* state) 334 { 335 struct group* gr = &state->group; 336 int appid; 337 int userid; 338 339 if (gid < AID_APP) { 340 errno = ENOENT; 341 return NULL; 342 } 343 344 print_app_uid_name(gid, state->group_name_buffer, sizeof state->group_name_buffer); 345 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 355 struct passwd* 356 getpwuid(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 372 struct passwd* 373 getpwnam(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 386 int 387 getgrouplist (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 398 char* 399 getlogin(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 410 struct group* 411 getgrgid(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 426 struct group* 427 getgrnam(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 442 struct netent* getnetbyname(const char *name) 443 { 444 fprintf(stderr, "FIX ME! implement getgrnam() %s:%d\n", __FILE__, __LINE__); 445 return NULL; 446 } 447 448 void endpwent(void) 449 { 450 } 451 452 struct mntent* getmntent(FILE* f) 453 { 454 fprintf(stderr, "FIX ME! implement getmntent() %s:%d\n", __FILE__, __LINE__); 455 return NULL; 456 } 457 458 char* ttyname(int fd) 459 { 460 fprintf(stderr, "FIX ME! implement ttyname() %s:%d\n", __FILE__, __LINE__); 461 return NULL; 462 } 463 464 int 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 470 struct 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 476 struct protoent *getprotobyname(const char *name) 477 { 478 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); 479 return NULL; 480 } 481 482 struct protoent *getprotobynumber(int proto) 483 { 484 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); 485 return NULL; 486 } 487 488 char* getusershell(void) 489 { 490 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); 491 return NULL; 492 } 493 494 void setusershell(void) 495 { 496 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); 497 } 498 499 void endusershell(void) 500 { 501 fprintf(stderr, "FIX ME! implement %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); 502 } 503