Home | History | Annotate | Download | only in bionic
      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 
     29 #include <ctype.h>
     30 #include <errno.h>
     31 #include <grp.h>
     32 #include <mntent.h>
     33 #include <pthread.h>
     34 #include <pwd.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 #include <unistd.h>
     39 
     40 #include "private/android_filesystem_config.h"
     41 #include "private/bionic_macros.h"
     42 #include "private/grp_pwd.h"
     43 #include "private/ErrnoRestorer.h"
     44 #include "private/libc_logging.h"
     45 
     46 // Generated android_ids array
     47 #include "generated_android_ids.h"
     48 
     49 // POSIX seems to envisage an implementation where the <pwd.h> functions are
     50 // implemented by brute-force searching with getpwent(3), and the <grp.h>
     51 // functions are implemented similarly with getgrent(3). This means that it's
     52 // okay for all the <grp.h> functions to share state, and all the <passwd.h>
     53 // functions to share state, but <grp.h> functions can't clobber <passwd.h>
     54 // functions' state and vice versa.
     55 #include "bionic/pthread_internal.h"
     56 static group_state_t* get_group_tls_buffer() {
     57   return &__get_bionic_tls().group;
     58 }
     59 
     60 static passwd_state_t* get_passwd_tls_buffer() {
     61   return &__get_bionic_tls().passwd;
     62 }
     63 
     64 static void init_group_state(group_state_t* state) {
     65   memset(state, 0, sizeof(group_state_t) - sizeof(state->getgrent_idx));
     66   state->group_.gr_mem = state->group_members_;
     67 }
     68 
     69 static group_state_t* __group_state() {
     70   group_state_t* result = get_group_tls_buffer();
     71   if (result != nullptr) {
     72     init_group_state(result);
     73   }
     74   return result;
     75 }
     76 
     77 static int do_getpw_r(int by_name, const char* name, uid_t uid,
     78                       passwd* dst, char* buf, size_t byte_count,
     79                       passwd** result) {
     80   // getpwnam_r and getpwuid_r don't modify errno, but library calls we
     81   // make might.
     82   ErrnoRestorer errno_restorer;
     83   *result = NULL;
     84 
     85   // Our implementation of getpwnam(3) and getpwuid(3) use thread-local
     86   // storage, so we can call them as long as we copy everything out
     87   // before returning.
     88   const passwd* src = by_name ? getpwnam(name) : getpwuid(uid); // NOLINT: see above.
     89 
     90   // POSIX allows failure to find a match to be considered a non-error.
     91   // Reporting success (0) but with *result NULL is glibc's behavior.
     92   if (src == NULL) {
     93     return (errno == ENOENT) ? 0 : errno;
     94   }
     95 
     96   // Work out where our strings will go in 'buf', and whether we've got
     97   // enough space.
     98   size_t required_byte_count = 0;
     99   dst->pw_name = buf;
    100   required_byte_count += strlen(src->pw_name) + 1;
    101   dst->pw_dir = buf + required_byte_count;
    102   required_byte_count += strlen(src->pw_dir) + 1;
    103   dst->pw_shell = buf + required_byte_count;
    104   required_byte_count += strlen(src->pw_shell) + 1;
    105   if (byte_count < required_byte_count) {
    106     return ERANGE;
    107   }
    108 
    109   // Copy the strings.
    110   snprintf(buf, byte_count, "%s%c%s%c%s", src->pw_name, 0, src->pw_dir, 0, src->pw_shell);
    111 
    112   // pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic.
    113   // Note: On LP32, we define pw_gecos to pw_passwd since they're both NULL.
    114   dst->pw_passwd = NULL;
    115 #if defined(__LP64__)
    116   dst->pw_gecos = NULL;
    117 #endif
    118 
    119   // Copy the integral fields.
    120   dst->pw_gid = src->pw_gid;
    121   dst->pw_uid = src->pw_uid;
    122 
    123   *result = dst;
    124   return 0;
    125 }
    126 
    127 int getpwnam_r(const char* name, passwd* pwd,
    128                char* buf, size_t byte_count, passwd** result) {
    129   return do_getpw_r(1, name, -1, pwd, buf, byte_count, result);
    130 }
    131 
    132 int getpwuid_r(uid_t uid, passwd* pwd,
    133                char* buf, size_t byte_count, passwd** result) {
    134   return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
    135 }
    136 
    137 static passwd* android_iinfo_to_passwd(passwd_state_t* state,
    138                                        const android_id_info* iinfo) {
    139   snprintf(state->name_buffer_, sizeof(state->name_buffer_), "%s", iinfo->name);
    140   snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
    141   snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
    142 
    143   passwd* pw = &state->passwd_;
    144   pw->pw_name  = state->name_buffer_;
    145   pw->pw_uid   = iinfo->aid;
    146   pw->pw_gid   = iinfo->aid;
    147   pw->pw_dir   = state->dir_buffer_;
    148   pw->pw_shell = state->sh_buffer_;
    149   return pw;
    150 }
    151 
    152 static group* android_iinfo_to_group(group_state_t* state,
    153                                      const android_id_info* iinfo) {
    154   snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_), "%s", iinfo->name);
    155 
    156   group* gr = &state->group_;
    157   gr->gr_name   = state->group_name_buffer_;
    158   gr->gr_gid    = iinfo->aid;
    159   gr->gr_mem[0] = gr->gr_name;
    160   return gr;
    161 }
    162 
    163 static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) {
    164   for (size_t n = 0; n < android_id_count; ++n) {
    165     if (android_ids[n].aid == id) {
    166       return android_iinfo_to_passwd(state, android_ids + n);
    167     }
    168   }
    169   return NULL;
    170 }
    171 
    172 static passwd* android_name_to_passwd(passwd_state_t* state, const char* name) {
    173   for (size_t n = 0; n < android_id_count; ++n) {
    174     if (!strcmp(android_ids[n].name, name)) {
    175       return android_iinfo_to_passwd(state, android_ids + n);
    176     }
    177   }
    178   return NULL;
    179 }
    180 
    181 static group* android_id_to_group(group_state_t* state, unsigned id) {
    182   for (size_t n = 0; n < android_id_count; ++n) {
    183     if (android_ids[n].aid == id) {
    184       return android_iinfo_to_group(state, android_ids + n);
    185     }
    186   }
    187   return NULL;
    188 }
    189 
    190 static group* android_name_to_group(group_state_t* state, const char* name) {
    191   for (size_t n = 0; n < android_id_count; ++n) {
    192     if (!strcmp(android_ids[n].name, name)) {
    193       return android_iinfo_to_group(state, android_ids + n);
    194     }
    195   }
    196   return NULL;
    197 }
    198 
    199 // Translate a user/group name to the corresponding user/group id.
    200 // all_a1234 -> 0 * AID_USER_OFFSET + AID_SHARED_GID_START + 1234 (group name only)
    201 // u0_a1234_cache -> 0 * AID_USER_OFFSET + AID_CACHE_GID_START + 1234 (group name only)
    202 // u0_a1234 -> 0 * AID_USER_OFFSET + AID_APP_START + 1234
    203 // u2_i1000 -> 2 * AID_USER_OFFSET + AID_ISOLATED_START + 1000
    204 // u1_system -> 1 * AID_USER_OFFSET + android_ids['system']
    205 // returns 0 and sets errno to ENOENT in case of error.
    206 static id_t app_id_from_name(const char* name, bool is_group) {
    207   char* end;
    208   unsigned long userid;
    209   bool is_shared_gid = false;
    210 
    211   if (is_group && name[0] == 'a' && name[1] == 'l' && name[2] == 'l') {
    212     end = const_cast<char*>(name+3);
    213     userid = 0;
    214     is_shared_gid = true;
    215   } else if (name[0] == 'u' && isdigit(name[1])) {
    216     userid = strtoul(name+1, &end, 10);
    217   } else {
    218     errno = ENOENT;
    219     return 0;
    220   }
    221 
    222   if (end[0] != '_' || end[1] == 0) {
    223     errno = ENOENT;
    224     return 0;
    225   }
    226 
    227   unsigned long appid = 0;
    228   if (end[1] == 'a' && isdigit(end[2])) {
    229     if (is_shared_gid) {
    230       // end will point to \0 if the strtoul below succeeds.
    231       appid = strtoul(end+2, &end, 10) + AID_SHARED_GID_START;
    232       if (appid > AID_SHARED_GID_END) {
    233         errno = ENOENT;
    234         return 0;
    235       }
    236     } else {
    237       // end will point to \0 if the strtoul below succeeds.
    238       appid = strtoul(end+2, &end, 10);
    239       if (is_group && !strcmp(end, "_cache")) {
    240         end += 6;
    241         appid += AID_CACHE_GID_START;
    242       } else {
    243         appid += AID_APP_START;
    244       }
    245     }
    246   } else if (end[1] == 'i' && isdigit(end[2])) {
    247     // end will point to \0 if the strtoul below succeeds.
    248     appid = strtoul(end+2, &end, 10) + AID_ISOLATED_START;
    249   } else {
    250     for (size_t n = 0; n < android_id_count; n++) {
    251       if (!strcmp(android_ids[n].name, end + 1)) {
    252         appid = android_ids[n].aid;
    253         // Move the end pointer to the null terminator.
    254         end += strlen(android_ids[n].name) + 1;
    255         break;
    256       }
    257     }
    258   }
    259 
    260   // Check that the entire string was consumed by one of the 3 cases above.
    261   if (end[0] != 0) {
    262     errno = ENOENT;
    263     return 0;
    264   }
    265 
    266   // Check that user id won't overflow.
    267   if (userid > 1000) {
    268     errno = ENOENT;
    269     return 0;
    270   }
    271 
    272   // Check that app id is within range.
    273   if (appid >= AID_USER_OFFSET) {
    274     errno = ENOENT;
    275     return 0;
    276   }
    277 
    278   return (appid + userid*AID_USER_OFFSET);
    279 }
    280 
    281 static void print_app_name_from_uid(const uid_t uid, char* buffer, const int bufferlen) {
    282   const uid_t appid = uid % AID_USER_OFFSET;
    283   const uid_t userid = uid / AID_USER_OFFSET;
    284   if (appid >= AID_ISOLATED_START) {
    285     snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
    286   } else if (appid < AID_APP_START) {
    287     for (size_t n = 0; n < android_id_count; n++) {
    288       if (android_ids[n].aid == appid) {
    289         snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);
    290         return;
    291       }
    292     }
    293   } else {
    294     snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START);
    295   }
    296 }
    297 
    298 static void print_app_name_from_gid(const gid_t gid, char* buffer, const int bufferlen) {
    299   const uid_t appid = gid % AID_USER_OFFSET;
    300   const uid_t userid = gid / AID_USER_OFFSET;
    301   if (appid >= AID_ISOLATED_START) {
    302     snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
    303   } else if (userid == 0 && appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END) {
    304     snprintf(buffer, bufferlen, "all_a%u", appid - AID_SHARED_GID_START);
    305   } else if (appid >= AID_CACHE_GID_START && appid <= AID_CACHE_GID_END) {
    306     snprintf(buffer, bufferlen, "u%u_a%u_cache", userid, appid - AID_CACHE_GID_START);
    307   } else if (appid < AID_APP_START) {
    308     for (size_t n = 0; n < android_id_count; n++) {
    309       if (android_ids[n].aid == appid) {
    310         snprintf(buffer, bufferlen, "u%u_%s", userid, android_ids[n].name);
    311         return;
    312       }
    313     }
    314   } else {
    315     snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START);
    316   }
    317 }
    318 
    319 // oem_XXXX -> uid
    320 //  Supported ranges:
    321 //   AID_OEM_RESERVED_START to AID_OEM_RESERVED_END (2900-2999)
    322 //   AID_OEM_RESERVED_2_START to AID_OEM_RESERVED_2_END (5000-5999)
    323 // Check OEM id is within range.
    324 static bool is_oem_id(id_t id) {
    325   return (((id >= AID_OEM_RESERVED_START) && (id <= AID_OEM_RESERVED_END)) ||
    326       ((id >= AID_OEM_RESERVED_2_START) && (id <= AID_OEM_RESERVED_2_END)));
    327 }
    328 
    329 // Translate an OEM name to the corresponding user/group id.
    330 static id_t oem_id_from_name(const char* name) {
    331   unsigned int id;
    332   if (sscanf(name, "oem_%u", &id) != 1) {
    333     return 0;
    334   }
    335   if (!is_oem_id(id)) {
    336     return 0;
    337   }
    338   return static_cast<id_t>(id);
    339 }
    340 
    341 static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
    342   if (!is_oem_id(uid)) {
    343     return NULL;
    344   }
    345 
    346   snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u", uid);
    347   snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
    348   snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
    349 
    350   passwd* pw = &state->passwd_;
    351   pw->pw_name  = state->name_buffer_;
    352   pw->pw_dir   = state->dir_buffer_;
    353   pw->pw_shell = state->sh_buffer_;
    354   pw->pw_uid   = uid;
    355   pw->pw_gid   = uid;
    356   return pw;
    357 }
    358 
    359 static group* oem_id_to_group(gid_t gid, group_state_t* state) {
    360   if (!is_oem_id(gid)) {
    361     return NULL;
    362   }
    363 
    364   snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_),
    365            "oem_%u", gid);
    366 
    367   group* gr = &state->group_;
    368   gr->gr_name   = state->group_name_buffer_;
    369   gr->gr_gid    = gid;
    370   gr->gr_mem[0] = gr->gr_name;
    371   return gr;
    372 }
    373 
    374 // Translate a uid into the corresponding name.
    375 // 0 to AID_APP_START-1                    -> "system", "radio", etc.
    376 // AID_APP_START to AID_ISOLATED_START-1   -> u0_a1234
    377 // AID_ISOLATED_START to AID_USER_OFFSET-1 -> u0_i1234
    378 // AID_USER_OFFSET+                        -> u1_radio, u1_a1234, u2_i1234, etc.
    379 // returns a passwd structure (sets errno to ENOENT on failure).
    380 static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
    381   if (uid < AID_APP_START) {
    382     errno = ENOENT;
    383     return NULL;
    384   }
    385 
    386   print_app_name_from_uid(uid, state->name_buffer_, sizeof(state->name_buffer_));
    387 
    388   const uid_t appid = uid % AID_USER_OFFSET;
    389   if (appid < AID_APP_START) {
    390       snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
    391   } else {
    392       snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data");
    393   }
    394 
    395   snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
    396 
    397   passwd* pw = &state->passwd_;
    398   pw->pw_name  = state->name_buffer_;
    399   pw->pw_dir   = state->dir_buffer_;
    400   pw->pw_shell = state->sh_buffer_;
    401   pw->pw_uid   = uid;
    402   pw->pw_gid   = uid;
    403   return pw;
    404 }
    405 
    406 // Translate a gid into the corresponding app_<gid>
    407 // group structure (sets errno to ENOENT on failure).
    408 static group* app_id_to_group(gid_t gid, group_state_t* state) {
    409   if (gid < AID_APP_START) {
    410     errno = ENOENT;
    411     return NULL;
    412   }
    413 
    414   print_app_name_from_gid(gid, state->group_name_buffer_, sizeof(state->group_name_buffer_));
    415 
    416   group* gr = &state->group_;
    417   gr->gr_name   = state->group_name_buffer_;
    418   gr->gr_gid    = gid;
    419   gr->gr_mem[0] = gr->gr_name;
    420   return gr;
    421 }
    422 
    423 passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
    424   passwd_state_t* state = get_passwd_tls_buffer();
    425   if (state == NULL) {
    426     return NULL;
    427   }
    428 
    429   passwd* pw = android_id_to_passwd(state, uid);
    430   if (pw != NULL) {
    431     return pw;
    432   }
    433   // Handle OEM range.
    434   pw = oem_id_to_passwd(uid, state);
    435   if (pw != NULL) {
    436     return pw;
    437   }
    438   return app_id_to_passwd(uid, state);
    439 }
    440 
    441 passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
    442   passwd_state_t* state = get_passwd_tls_buffer();
    443   if (state == NULL) {
    444     return NULL;
    445   }
    446 
    447   passwd* pw = android_name_to_passwd(state, login);
    448   if (pw != NULL) {
    449     return pw;
    450   }
    451   // Handle OEM range.
    452   pw = oem_id_to_passwd(oem_id_from_name(login), state);
    453   if (pw != NULL) {
    454     return pw;
    455   }
    456   return app_id_to_passwd(app_id_from_name(login, false), state);
    457 }
    458 
    459 // All users are in just one group, the one passed in.
    460 int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
    461   if (*ngroups < 1) {
    462     *ngroups = 1;
    463     return -1;
    464   }
    465   groups[0] = group;
    466   return (*ngroups = 1);
    467 }
    468 
    469 char* getlogin() { // NOLINT: implementing bad function.
    470   passwd *pw = getpwuid(getuid()); // NOLINT: implementing bad function in terms of bad function.
    471   return (pw != NULL) ? pw->pw_name : NULL;
    472 }
    473 
    474 void setpwent() {
    475   passwd_state_t* state = get_passwd_tls_buffer();
    476   if (state) {
    477     state->getpwent_idx = 0;
    478   }
    479 }
    480 
    481 void endpwent() {
    482   setpwent();
    483 }
    484 
    485 passwd* getpwent() {
    486   passwd_state_t* state = get_passwd_tls_buffer();
    487   if (state == NULL) {
    488     return NULL;
    489   }
    490   if (state->getpwent_idx < 0) {
    491     return NULL;
    492   }
    493 
    494   size_t start = 0;
    495   ssize_t end = android_id_count;
    496   if (state->getpwent_idx < end) {
    497     return android_iinfo_to_passwd(state, android_ids + state->getpwent_idx++);
    498   }
    499 
    500   start = end;
    501   end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
    502 
    503   if (state->getpwent_idx < end) {
    504     return oem_id_to_passwd(
    505         state->getpwent_idx++ - start + AID_OEM_RESERVED_START, state);
    506   }
    507 
    508   start = end;
    509   end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
    510 
    511   if (state->getpwent_idx < end) {
    512     return oem_id_to_passwd(
    513         state->getpwent_idx++ - start + AID_OEM_RESERVED_2_START, state);
    514   }
    515 
    516   start = end;
    517   end += AID_USER_OFFSET - AID_APP_START; // Do not expose higher users
    518 
    519   if (state->getpwent_idx < end) {
    520     return app_id_to_passwd(state->getpwent_idx++ - start + AID_APP_START, state);
    521   }
    522 
    523   // We are not reporting u1_a* and higher or we will be here forever
    524   state->getpwent_idx = -1;
    525   return NULL;
    526 }
    527 
    528 static group* getgrgid_internal(gid_t gid, group_state_t* state) {
    529   group* grp = android_id_to_group(state, gid);
    530   if (grp != NULL) {
    531     return grp;
    532   }
    533   // Handle OEM range.
    534   grp = oem_id_to_group(gid, state);
    535   if (grp != NULL) {
    536     return grp;
    537   }
    538   return app_id_to_group(gid, state);
    539 }
    540 
    541 group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
    542   group_state_t* state = __group_state();
    543   if (state == NULL) {
    544     return NULL;
    545   }
    546   return getgrgid_internal(gid, state);
    547 }
    548 
    549 static group* getgrnam_internal(const char* name, group_state_t* state) {
    550   group* grp = android_name_to_group(state, name);
    551   if (grp != NULL) {
    552     return grp;
    553   }
    554   // Handle OEM range.
    555   grp = oem_id_to_group(oem_id_from_name(name), state);
    556   if (grp != NULL) {
    557     return grp;
    558   }
    559   return app_id_to_group(app_id_from_name(name, true), state);
    560 }
    561 
    562 group* getgrnam(const char* name) { // NOLINT: implementing bad function.
    563   group_state_t* state = __group_state();
    564   if (state == NULL) {
    565     return NULL;
    566   }
    567   return getgrnam_internal(name, state);
    568 }
    569 
    570 static int getgroup_r(bool by_name, const char* name, gid_t gid, struct group* grp, char* buf,
    571                       size_t buflen, struct group** result) {
    572   ErrnoRestorer errno_restorer;
    573   *result = NULL;
    574   char* p = reinterpret_cast<char*>(
    575       BIONIC_ALIGN(reinterpret_cast<uintptr_t>(buf), sizeof(uintptr_t)));
    576   if (p + sizeof(group_state_t) > buf + buflen) {
    577     return ERANGE;
    578   }
    579   group_state_t* state = reinterpret_cast<group_state_t*>(p);
    580   init_group_state(state);
    581   group* retval = (by_name ? getgrnam_internal(name, state) : getgrgid_internal(gid, state));
    582   if (retval != NULL) {
    583     *grp = *retval;
    584     *result = grp;
    585     return 0;
    586   }
    587   return errno;
    588 }
    589 
    590 int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) {
    591   return getgroup_r(false, NULL, gid, grp, buf, buflen, result);
    592 }
    593 
    594 int getgrnam_r(const char* name, struct group* grp, char* buf, size_t buflen,
    595                struct group **result) {
    596   return getgroup_r(true, name, 0, grp, buf, buflen, result);
    597 }
    598 
    599 void setgrent() {
    600   group_state_t* state = get_group_tls_buffer();
    601   if (state) {
    602     state->getgrent_idx = 0;
    603   }
    604 }
    605 
    606 void endgrent() {
    607   setgrent();
    608 }
    609 
    610 group* getgrent() {
    611   group_state_t* state = get_group_tls_buffer();
    612   if (state == NULL) {
    613     return NULL;
    614   }
    615   if (state->getgrent_idx < 0) {
    616     return NULL;
    617   }
    618 
    619   size_t start = 0;
    620   ssize_t end = android_id_count;
    621   if (state->getgrent_idx < end) {
    622     init_group_state(state);
    623     return android_iinfo_to_group(state, android_ids + state->getgrent_idx++);
    624   }
    625 
    626   start = end;
    627   end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
    628 
    629   if (state->getgrent_idx < end) {
    630     init_group_state(state);
    631     return oem_id_to_group(
    632         state->getgrent_idx++ - start + AID_OEM_RESERVED_START, state);
    633   }
    634 
    635   start = end;
    636   end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
    637 
    638   if (state->getgrent_idx < end) {
    639     init_group_state(state);
    640     return oem_id_to_group(
    641         state->getgrent_idx++ - start + AID_OEM_RESERVED_2_START, state);
    642   }
    643 
    644   start = end;
    645   end += AID_USER_OFFSET - AID_APP_START; // Do not expose higher groups
    646 
    647   if (state->getgrent_idx < end) {
    648     init_group_state(state);
    649     return app_id_to_group(state->getgrent_idx++ - start + AID_APP_START, state);
    650   }
    651 
    652   // We are not reporting u1_a* and higher or we will be here forever
    653   state->getgrent_idx = -1;
    654   return NULL;
    655 }
    656