2016-04-05 18:09:46 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
#include "private/grp_pwd.h"
|
|
|
|
|
2019-04-24 20:12:59 +02:00
|
|
|
#include <android/api-level.h>
|
2016-04-05 18:09:46 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <mntent.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2019-04-24 20:12:59 +02:00
|
|
|
#include <sys/system_properties.h>
|
2019-04-25 19:34:07 +02:00
|
|
|
#include <sys/types.h>
|
2016-04-05 18:09:46 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
#include "private/ErrnoRestorer.h"
|
2016-04-05 18:09:46 +02:00
|
|
|
#include "private/android_filesystem_config.h"
|
2019-12-20 01:35:51 +01:00
|
|
|
#include "platform/bionic/macros.h"
|
2016-04-05 18:09:46 +02:00
|
|
|
|
2016-12-14 00:47:25 +01:00
|
|
|
// Generated android_ids array
|
|
|
|
#include "generated_android_ids.h"
|
2018-02-03 01:10:07 +01:00
|
|
|
#include "grp_pwd_file.h"
|
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
static PasswdFile passwd_files[] = {
|
|
|
|
{ "/system/etc/passwd", "system_" },
|
|
|
|
{ "/vendor/etc/passwd", "vendor_" },
|
|
|
|
{ "/odm/etc/passwd", "odm_" },
|
|
|
|
{ "/product/etc/passwd", "product_" },
|
|
|
|
{ "/system_ext/etc/passwd", "system_ext_" },
|
|
|
|
};
|
|
|
|
|
|
|
|
static GroupFile group_files[] = {
|
|
|
|
{ "/system/etc/group", "system_" },
|
|
|
|
{ "/vendor/etc/group", "vendor_" },
|
|
|
|
{ "/odm/etc/group", "odm_" },
|
|
|
|
{ "/product/etc/group", "product_" },
|
|
|
|
{ "/system_ext/etc/group", "system_ext_" },
|
|
|
|
};
|
2016-12-14 00:47:25 +01:00
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// POSIX seems to envisage an implementation where the <pwd.h> functions are
|
|
|
|
// implemented by brute-force searching with getpwent(3), and the <grp.h>
|
|
|
|
// functions are implemented similarly with getgrent(3). This means that it's
|
|
|
|
// okay for all the <grp.h> functions to share state, and all the <passwd.h>
|
|
|
|
// functions to share state, but <grp.h> functions can't clobber <passwd.h>
|
|
|
|
// functions' state and vice versa.
|
2017-02-22 21:19:05 +01:00
|
|
|
#include "bionic/pthread_internal.h"
|
2016-04-05 18:09:46 +02:00
|
|
|
|
|
|
|
static void init_group_state(group_state_t* state) {
|
2016-04-06 19:35:48 +02:00
|
|
|
memset(state, 0, sizeof(group_state_t) - sizeof(state->getgrent_idx));
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
state->group_.gr_name = state->group_name_buffer_;
|
2016-04-05 18:09:46 +02:00
|
|
|
state->group_.gr_mem = state->group_members_;
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
state->group_.gr_mem[0] = state->group_.gr_name;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
static group_state_t* get_group_tls_buffer() {
|
|
|
|
auto result = &__get_bionic_tls().group;
|
|
|
|
init_group_state(result);
|
2016-04-05 18:09:46 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
static void init_passwd_state(passwd_state_t* state) {
|
|
|
|
memset(state, 0, sizeof(passwd_state_t) - sizeof(state->getpwent_idx));
|
|
|
|
state->passwd_.pw_name = state->name_buffer_;
|
|
|
|
state->passwd_.pw_dir = state->dir_buffer_;
|
|
|
|
state->passwd_.pw_shell = state->sh_buffer_;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
static passwd_state_t* get_passwd_tls_buffer() {
|
|
|
|
auto result = &__get_bionic_tls().passwd;
|
|
|
|
init_passwd_state(result);
|
|
|
|
return result;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static passwd* android_iinfo_to_passwd(passwd_state_t* state,
|
|
|
|
const android_id_info* iinfo) {
|
|
|
|
snprintf(state->name_buffer_, sizeof(state->name_buffer_), "%s", iinfo->name);
|
|
|
|
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
|
2019-02-17 18:38:23 +01:00
|
|
|
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/bin/sh");
|
2016-04-05 18:09:46 +02:00
|
|
|
|
|
|
|
passwd* pw = &state->passwd_;
|
|
|
|
pw->pw_uid = iinfo->aid;
|
|
|
|
pw->pw_gid = iinfo->aid;
|
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
|
|
|
|
static group* android_iinfo_to_group(group_state_t* state,
|
|
|
|
const android_id_info* iinfo) {
|
|
|
|
snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_), "%s", iinfo->name);
|
|
|
|
|
|
|
|
group* gr = &state->group_;
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
gr->gr_gid = iinfo->aid;
|
2016-04-05 18:09:46 +02:00
|
|
|
return gr;
|
|
|
|
}
|
|
|
|
|
2019-04-24 22:35:39 +02:00
|
|
|
static const android_id_info* find_android_id_info(unsigned id) {
|
2016-04-05 18:09:46 +02:00
|
|
|
for (size_t n = 0; n < android_id_count; ++n) {
|
|
|
|
if (android_ids[n].aid == id) {
|
2019-04-24 22:35:39 +02:00
|
|
|
return &android_ids[n];
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
2019-04-24 22:35:39 +02:00
|
|
|
static const android_id_info* find_android_id_info(const char* name) {
|
2016-04-05 18:09:46 +02:00
|
|
|
for (size_t n = 0; n < android_id_count; ++n) {
|
|
|
|
if (!strcmp(android_ids[n].name, name)) {
|
2019-04-24 22:35:39 +02:00
|
|
|
return &android_ids[n];
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
2017-11-14 17:50:43 +01:00
|
|
|
// These are a list of the reserved app ranges, and should never contain anything below
|
|
|
|
// AID_APP_START. They exist per user, so a given uid/gid modulo AID_USER_OFFSET will map
|
|
|
|
// to these ranges.
|
2019-04-25 19:34:07 +02:00
|
|
|
struct IdRange {
|
|
|
|
id_t start;
|
|
|
|
id_t end;
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr IdRange user_ranges[] = {
|
|
|
|
{ AID_APP_START, AID_APP_END },
|
|
|
|
{ AID_ISOLATED_START, AID_ISOLATED_END },
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr IdRange group_ranges[] = {
|
2017-11-14 17:50:43 +01:00
|
|
|
{ AID_APP_START, AID_APP_END },
|
|
|
|
{ AID_CACHE_GID_START, AID_CACHE_GID_END },
|
|
|
|
{ AID_EXT_GID_START, AID_EXT_GID_END },
|
|
|
|
{ AID_EXT_CACHE_GID_START, AID_EXT_CACHE_GID_END },
|
|
|
|
{ AID_SHARED_GID_START, AID_SHARED_GID_END },
|
|
|
|
{ AID_ISOLATED_START, AID_ISOLATED_END },
|
|
|
|
};
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
template <class T, size_t N>
|
|
|
|
static constexpr bool verify_user_ranges_ascending(T (&ranges)[N]) {
|
|
|
|
auto array_size = N;
|
2017-11-14 17:50:43 +01:00
|
|
|
if (array_size < 2) return false;
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
if (ranges[0].start > ranges[0].end) return false;
|
2017-11-14 17:50:43 +01:00
|
|
|
|
|
|
|
for (size_t i = 1; i < array_size; ++i) {
|
2019-04-25 19:34:07 +02:00
|
|
|
if (ranges[i].start > ranges[i].end) return false;
|
|
|
|
if (ranges[i - 1].end > ranges[i].start) return false;
|
2017-11-14 17:50:43 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
static_assert(verify_user_ranges_ascending(user_ranges), "user_ranges must have ascending ranges");
|
|
|
|
static_assert(verify_user_ranges_ascending(group_ranges), "user_ranges must have ascending ranges");
|
|
|
|
|
|
|
|
// This list comes from PackageManagerService.java, where platform AIDs are added to list of valid
|
|
|
|
// AIDs for packages via addSharedUserLPw().
|
|
|
|
static constexpr const id_t secondary_user_platform_ids[] = {
|
|
|
|
AID_SYSTEM, AID_RADIO, AID_LOG, AID_NFC, AID_BLUETOOTH,
|
|
|
|
AID_SHELL, AID_SECURE_ELEMENT, AID_NETWORK_STACK,
|
|
|
|
};
|
2017-11-14 17:50:43 +01:00
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
static bool platform_id_secondary_user_allowed(id_t id) {
|
|
|
|
for (const auto& allowed_id : secondary_user_platform_ids) {
|
|
|
|
if (allowed_id == id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_valid_app_id(id_t id, bool is_group) {
|
2017-11-14 17:50:43 +01:00
|
|
|
id_t appid = id % AID_USER_OFFSET;
|
|
|
|
|
|
|
|
// AID_OVERFLOWUID is never a valid app id, so we explicitly return false to ensure this.
|
|
|
|
// This is true across all users, as there is no reason to ever map this id into any user range.
|
|
|
|
if (appid == AID_OVERFLOWUID) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
auto ranges_size = is_group ? arraysize(group_ranges) : arraysize(user_ranges);
|
|
|
|
auto ranges = is_group ? group_ranges : user_ranges;
|
|
|
|
|
|
|
|
// If we're checking an appid that resolves below the user range, then it's a platform AID for a
|
|
|
|
// seconary user. We only allow a reduced set of these, so we must check that it is allowed.
|
|
|
|
if (appid < ranges[0].start && platform_id_secondary_user_allowed(appid)) {
|
2017-11-14 17:50:43 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
// The shared GID range is only valid for the first user.
|
|
|
|
if (appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END && appid != id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-14 17:50:43 +01:00
|
|
|
// Otherwise check that the appid is in one of the reserved ranges.
|
2019-04-25 19:34:07 +02:00
|
|
|
for (size_t i = 0; i < ranges_size; ++i) {
|
|
|
|
if (appid >= ranges[i].start && appid <= ranges[i].end) {
|
2017-11-14 17:50:43 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This provides an iterater for app_ids within the first user's app id's.
|
2019-04-25 19:34:07 +02:00
|
|
|
static id_t get_next_app_id(id_t current_id, bool is_group) {
|
|
|
|
auto ranges_size = is_group ? arraysize(group_ranges) : arraysize(user_ranges);
|
|
|
|
auto ranges = is_group ? group_ranges : user_ranges;
|
|
|
|
|
|
|
|
// If current_id is below the first of the ranges, then we're uninitialized, and return the first
|
|
|
|
// valid id.
|
|
|
|
if (current_id < ranges[0].start) {
|
|
|
|
return ranges[0].start;
|
2017-11-14 17:50:43 +01:00
|
|
|
}
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
id_t incremented_id = current_id + 1;
|
2017-11-14 17:50:43 +01:00
|
|
|
|
|
|
|
// Check to see if our incremented_id is between two ranges, and if so, return the beginning of
|
|
|
|
// the next valid range.
|
2019-04-25 19:34:07 +02:00
|
|
|
for (size_t i = 1; i < ranges_size; ++i) {
|
|
|
|
if (incremented_id > ranges[i - 1].end && incremented_id < ranges[i].start) {
|
|
|
|
return ranges[i].start;
|
2017-11-14 17:50:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if our incremented_id is above final range, and return -1 to indicate that we've
|
|
|
|
// completed if so.
|
2019-04-25 19:34:07 +02:00
|
|
|
if (incremented_id > ranges[ranges_size - 1].end) {
|
2017-11-14 17:50:43 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise the incremented_id is valid, so return it.
|
|
|
|
return incremented_id;
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// Translate a user/group name to the corresponding user/group id.
|
2016-12-13 22:03:19 +01:00
|
|
|
// all_a1234 -> 0 * AID_USER_OFFSET + AID_SHARED_GID_START + 1234 (group name only)
|
2019-04-25 19:34:07 +02:00
|
|
|
// u0_a1234_ext_cache -> 0 * AID_USER_OFFSET + AID_EXT_CACHE_GID_START + 1234 (group name only)
|
|
|
|
// u0_a1234_ext -> 0 * AID_USER_OFFSET + AID_EXT_GID_START + 1234 (group name only)
|
2016-12-13 22:03:19 +01:00
|
|
|
// u0_a1234_cache -> 0 * AID_USER_OFFSET + AID_CACHE_GID_START + 1234 (group name only)
|
|
|
|
// u0_a1234 -> 0 * AID_USER_OFFSET + AID_APP_START + 1234
|
|
|
|
// u2_i1000 -> 2 * AID_USER_OFFSET + AID_ISOLATED_START + 1000
|
|
|
|
// u1_system -> 1 * AID_USER_OFFSET + android_ids['system']
|
2016-04-05 18:09:46 +02:00
|
|
|
// returns 0 and sets errno to ENOENT in case of error.
|
|
|
|
static id_t app_id_from_name(const char* name, bool is_group) {
|
|
|
|
char* end;
|
|
|
|
unsigned long userid;
|
|
|
|
bool is_shared_gid = false;
|
|
|
|
|
|
|
|
if (is_group && name[0] == 'a' && name[1] == 'l' && name[2] == 'l') {
|
|
|
|
end = const_cast<char*>(name+3);
|
|
|
|
userid = 0;
|
|
|
|
is_shared_gid = true;
|
|
|
|
} else if (name[0] == 'u' && isdigit(name[1])) {
|
|
|
|
userid = strtoul(name+1, &end, 10);
|
|
|
|
} else {
|
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end[0] != '_' || end[1] == 0) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long appid = 0;
|
|
|
|
if (end[1] == 'a' && isdigit(end[2])) {
|
|
|
|
if (is_shared_gid) {
|
|
|
|
// end will point to \0 if the strtoul below succeeds.
|
|
|
|
appid = strtoul(end+2, &end, 10) + AID_SHARED_GID_START;
|
|
|
|
if (appid > AID_SHARED_GID_END) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// end will point to \0 if the strtoul below succeeds.
|
2016-12-13 22:03:19 +01:00
|
|
|
appid = strtoul(end+2, &end, 10);
|
2019-04-25 19:34:07 +02:00
|
|
|
if (is_group) {
|
|
|
|
if (!strcmp(end, "_ext_cache")) {
|
|
|
|
end += 10;
|
|
|
|
appid += AID_EXT_CACHE_GID_START;
|
|
|
|
} else if (!strcmp(end, "_ext")) {
|
|
|
|
end += 4;
|
|
|
|
appid += AID_EXT_GID_START;
|
|
|
|
} else if (!strcmp(end, "_cache")) {
|
|
|
|
end += 6;
|
|
|
|
appid += AID_CACHE_GID_START;
|
|
|
|
} else {
|
|
|
|
appid += AID_APP_START;
|
|
|
|
}
|
2016-12-13 22:03:19 +01:00
|
|
|
} else {
|
|
|
|
appid += AID_APP_START;
|
|
|
|
}
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
} else if (end[1] == 'i' && isdigit(end[2])) {
|
|
|
|
// end will point to \0 if the strtoul below succeeds.
|
|
|
|
appid = strtoul(end+2, &end, 10) + AID_ISOLATED_START;
|
2019-04-24 22:35:39 +02:00
|
|
|
} else if (auto* android_id_info = find_android_id_info(end + 1); android_id_info != nullptr) {
|
|
|
|
appid = android_id_info->aid;
|
|
|
|
end += strlen(android_id_info->name) + 1;
|
2019-04-25 19:34:07 +02:00
|
|
|
if (!platform_id_secondary_user_allowed(appid)) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the entire string was consumed by one of the 3 cases above.
|
|
|
|
if (end[0] != 0) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that user id won't overflow.
|
|
|
|
if (userid > 1000) {
|
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that app id is within range.
|
2016-12-13 22:03:19 +01:00
|
|
|
if (appid >= AID_USER_OFFSET) {
|
2016-04-05 18:09:46 +02:00
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-13 22:03:19 +01:00
|
|
|
return (appid + userid*AID_USER_OFFSET);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void print_app_name_from_uid(const uid_t uid, char* buffer, const int bufferlen) {
|
2016-12-13 22:03:19 +01:00
|
|
|
const uid_t appid = uid % AID_USER_OFFSET;
|
|
|
|
const uid_t userid = uid / AID_USER_OFFSET;
|
2016-04-05 18:09:46 +02:00
|
|
|
if (appid >= AID_ISOLATED_START) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
|
2016-12-13 22:03:19 +01:00
|
|
|
} else if (appid < AID_APP_START) {
|
2019-04-24 22:35:39 +02:00
|
|
|
if (auto* android_id_info = find_android_id_info(appid); android_id_info != nullptr) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_%s", userid, android_id_info->name);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
} else {
|
2016-12-13 22:03:19 +01:00
|
|
|
snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_app_name_from_gid(const gid_t gid, char* buffer, const int bufferlen) {
|
2016-12-13 22:03:19 +01:00
|
|
|
const uid_t appid = gid % AID_USER_OFFSET;
|
|
|
|
const uid_t userid = gid / AID_USER_OFFSET;
|
2016-04-05 18:09:46 +02:00
|
|
|
if (appid >= AID_ISOLATED_START) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_i%u", userid, appid - AID_ISOLATED_START);
|
|
|
|
} else if (userid == 0 && appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END) {
|
|
|
|
snprintf(buffer, bufferlen, "all_a%u", appid - AID_SHARED_GID_START);
|
2019-04-25 19:34:07 +02:00
|
|
|
} else if (appid >= AID_EXT_CACHE_GID_START && appid <= AID_EXT_CACHE_GID_END) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_a%u_ext_cache", userid, appid - AID_EXT_CACHE_GID_START);
|
|
|
|
} else if (appid >= AID_EXT_GID_START && appid <= AID_EXT_GID_END) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_a%u_ext", userid, appid - AID_EXT_GID_START);
|
2016-12-13 22:03:19 +01:00
|
|
|
} else if (appid >= AID_CACHE_GID_START && appid <= AID_CACHE_GID_END) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_a%u_cache", userid, appid - AID_CACHE_GID_START);
|
|
|
|
} else if (appid < AID_APP_START) {
|
2019-04-24 22:35:39 +02:00
|
|
|
if (auto* android_id_info = find_android_id_info(appid); android_id_info != nullptr) {
|
|
|
|
snprintf(buffer, bufferlen, "u%u_%s", userid, android_id_info->name);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
} else {
|
2016-12-13 22:03:19 +01:00
|
|
|
snprintf(buffer, bufferlen, "u%u_a%u", userid, appid - AID_APP_START);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-24 20:12:59 +02:00
|
|
|
static bool device_launched_before_api_29() {
|
|
|
|
// Check if ro.product.first_api_level is set to a value > 0 and < 29, if so, this device was
|
|
|
|
// launched before API 29 (Q). Any other value is considered to be either in development or
|
|
|
|
// launched after.
|
|
|
|
// Cache the value as __system_property_get() is expensive and this may be called often.
|
|
|
|
static bool result = [] {
|
|
|
|
char value[PROP_VALUE_MAX] = { 0 };
|
|
|
|
if (__system_property_get("ro.product.first_api_level", value) == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int value_int = atoi(value);
|
|
|
|
return value_int != 0 && value_int < 29;
|
|
|
|
}();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:24:59 +02:00
|
|
|
// oem_XXXX -> uid
|
|
|
|
// Supported ranges:
|
|
|
|
// AID_OEM_RESERVED_START to AID_OEM_RESERVED_END (2900-2999)
|
|
|
|
// AID_OEM_RESERVED_2_START to AID_OEM_RESERVED_2_END (5000-5999)
|
|
|
|
// Check OEM id is within range.
|
|
|
|
static bool is_oem_id(id_t id) {
|
2019-04-24 20:12:59 +02:00
|
|
|
// Upgrading devices launched before API level 29 may not comply with the below check.
|
|
|
|
// Due to the difficulty in changing uids after launch, it is waived for these devices.
|
|
|
|
// The legacy range:
|
|
|
|
// AID_OEM_RESERVED_START to AID_EVERYBODY (2900-9996), excluding builtin AIDs.
|
|
|
|
if (device_launched_before_api_29() && id >= AID_OEM_RESERVED_START && id < AID_EVERYBODY &&
|
|
|
|
find_android_id_info(id) == nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (id >= AID_OEM_RESERVED_START && id <= AID_OEM_RESERVED_END) ||
|
|
|
|
(id >= AID_OEM_RESERVED_2_START && id <= AID_OEM_RESERVED_2_END);
|
2016-04-05 18:24:59 +02:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// Translate an OEM name to the corresponding user/group id.
|
|
|
|
static id_t oem_id_from_name(const char* name) {
|
|
|
|
unsigned int id;
|
|
|
|
if (sscanf(name, "oem_%u", &id) != 1) {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-04-05 18:24:59 +02:00
|
|
|
if (!is_oem_id(id)) {
|
2016-04-05 18:09:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2016-04-05 18:24:59 +02:00
|
|
|
return static_cast<id_t>(id);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static passwd* oem_id_to_passwd(uid_t uid, passwd_state_t* state) {
|
2019-02-17 18:38:23 +01:00
|
|
|
for (auto& passwd_file : passwd_files) {
|
|
|
|
if (passwd_file.FindById(uid, state)) {
|
|
|
|
return &state->passwd_;
|
|
|
|
}
|
2018-02-03 01:10:07 +01:00
|
|
|
}
|
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
if (!is_oem_id(uid)) {
|
|
|
|
return nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:24:59 +02:00
|
|
|
snprintf(state->name_buffer_, sizeof(state->name_buffer_), "oem_%u", uid);
|
2016-04-05 18:09:46 +02:00
|
|
|
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
|
2019-02-17 18:38:23 +01:00
|
|
|
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/bin/sh");
|
2016-04-05 18:09:46 +02:00
|
|
|
|
|
|
|
passwd* pw = &state->passwd_;
|
|
|
|
pw->pw_uid = uid;
|
|
|
|
pw->pw_gid = uid;
|
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
|
|
|
|
static group* oem_id_to_group(gid_t gid, group_state_t* state) {
|
2019-02-17 18:38:23 +01:00
|
|
|
for (auto& group_file : group_files) {
|
|
|
|
if (group_file.FindById(gid, state)) {
|
|
|
|
return &state->group_;
|
|
|
|
}
|
2018-02-03 01:10:07 +01:00
|
|
|
}
|
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
if (!is_oem_id(gid)) {
|
|
|
|
return nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(state->group_name_buffer_, sizeof(state->group_name_buffer_),
|
2016-04-05 18:24:59 +02:00
|
|
|
"oem_%u", gid);
|
2016-04-05 18:09:46 +02:00
|
|
|
|
|
|
|
group* gr = &state->group_;
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
gr->gr_gid = gid;
|
2016-04-05 18:09:46 +02:00
|
|
|
return gr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate a uid into the corresponding name.
|
2016-12-13 22:03:19 +01:00
|
|
|
// 0 to AID_APP_START-1 -> "system", "radio", etc.
|
|
|
|
// AID_APP_START to AID_ISOLATED_START-1 -> u0_a1234
|
|
|
|
// AID_ISOLATED_START to AID_USER_OFFSET-1 -> u0_i1234
|
|
|
|
// AID_USER_OFFSET+ -> u1_radio, u1_a1234, u2_i1234, etc.
|
2016-04-05 18:09:46 +02:00
|
|
|
// returns a passwd structure (sets errno to ENOENT on failure).
|
|
|
|
static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
|
2019-04-25 19:34:07 +02:00
|
|
|
if (uid < AID_APP_START || !is_valid_app_id(uid, false)) {
|
2016-04-05 18:09:46 +02:00
|
|
|
errno = ENOENT;
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
print_app_name_from_uid(uid, state->name_buffer_, sizeof(state->name_buffer_));
|
|
|
|
|
2016-12-13 22:03:19 +01:00
|
|
|
const uid_t appid = uid % AID_USER_OFFSET;
|
|
|
|
if (appid < AID_APP_START) {
|
2016-04-05 18:09:46 +02:00
|
|
|
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
|
|
|
|
} else {
|
|
|
|
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/data");
|
|
|
|
}
|
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/bin/sh");
|
2016-04-05 18:09:46 +02:00
|
|
|
|
|
|
|
passwd* pw = &state->passwd_;
|
|
|
|
pw->pw_uid = uid;
|
|
|
|
pw->pw_gid = uid;
|
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate a gid into the corresponding app_<gid>
|
|
|
|
// group structure (sets errno to ENOENT on failure).
|
|
|
|
static group* app_id_to_group(gid_t gid, group_state_t* state) {
|
2019-04-25 19:34:07 +02:00
|
|
|
if (gid < AID_APP_START || !is_valid_app_id(gid, true)) {
|
2016-04-05 18:09:46 +02:00
|
|
|
errno = ENOENT;
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
print_app_name_from_gid(gid, state->group_name_buffer_, sizeof(state->group_name_buffer_));
|
|
|
|
|
|
|
|
group* gr = &state->group_;
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
gr->gr_gid = gid;
|
2016-04-05 18:09:46 +02:00
|
|
|
return gr;
|
|
|
|
}
|
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
passwd* getpwuid_internal(uid_t uid, passwd_state_t* state) {
|
2019-04-24 22:35:39 +02:00
|
|
|
if (auto* android_id_info = find_android_id_info(uid); android_id_info != nullptr) {
|
|
|
|
return android_iinfo_to_passwd(state, android_id_info);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
2019-04-24 22:35:39 +02:00
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// Handle OEM range.
|
2019-04-24 22:35:39 +02:00
|
|
|
passwd* pw = oem_id_to_passwd(uid, state);
|
2018-08-03 02:31:13 +02:00
|
|
|
if (pw != nullptr) {
|
2016-04-05 18:09:46 +02:00
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
return app_id_to_passwd(uid, state);
|
|
|
|
}
|
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
2017-02-22 21:19:05 +01:00
|
|
|
passwd_state_t* state = get_passwd_tls_buffer();
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
return getpwuid_internal(uid, state);
|
|
|
|
}
|
2016-04-05 18:09:46 +02:00
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
passwd* getpwnam_internal(const char* login, passwd_state_t* state) {
|
2019-04-24 22:35:39 +02:00
|
|
|
if (auto* android_id_info = find_android_id_info(login); android_id_info != nullptr) {
|
|
|
|
return android_iinfo_to_passwd(state, android_id_info);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
2018-02-03 01:10:07 +01:00
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
for (auto& passwd_file : passwd_files) {
|
|
|
|
if (passwd_file.FindByName(login, state)) {
|
2018-02-03 01:10:07 +01:00
|
|
|
return &state->passwd_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// Handle OEM range.
|
2019-04-24 22:35:39 +02:00
|
|
|
passwd* pw = oem_id_to_passwd(oem_id_from_name(login), state);
|
2018-08-03 02:31:13 +02:00
|
|
|
if (pw != nullptr) {
|
2016-04-05 18:09:46 +02:00
|
|
|
return pw;
|
|
|
|
}
|
|
|
|
return app_id_to_passwd(app_id_from_name(login, false), state);
|
|
|
|
}
|
|
|
|
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
|
|
|
passwd_state_t* state = get_passwd_tls_buffer();
|
|
|
|
return getpwnam_internal(login, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getpasswd_r(bool by_name, const char* name, uid_t uid, struct passwd* pwd, char* buf,
|
|
|
|
size_t buflen, struct passwd** result) {
|
|
|
|
ErrnoRestorer errno_restorer;
|
|
|
|
*result = nullptr;
|
|
|
|
char* p =
|
|
|
|
reinterpret_cast<char*>(__BIONIC_ALIGN(reinterpret_cast<uintptr_t>(buf), sizeof(uintptr_t)));
|
|
|
|
if (p + sizeof(passwd_state_t) > buf + buflen) {
|
|
|
|
return ERANGE;
|
|
|
|
}
|
|
|
|
passwd_state_t* state = reinterpret_cast<passwd_state_t*>(p);
|
|
|
|
init_passwd_state(state);
|
|
|
|
passwd* retval = (by_name ? getpwnam_internal(name, state) : getpwuid_internal(uid, state));
|
|
|
|
if (retval != nullptr) {
|
|
|
|
*pwd = *retval;
|
|
|
|
*result = pwd;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getpwnam_r(const char* name, passwd* pwd, char* buf, size_t byte_count, passwd** result) {
|
|
|
|
return getpasswd_r(true, name, -1, pwd, buf, byte_count, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
int getpwuid_r(uid_t uid, passwd* pwd, char* buf, size_t byte_count, passwd** result) {
|
|
|
|
return getpasswd_r(false, nullptr, uid, pwd, buf, byte_count, result);
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// All users are in just one group, the one passed in.
|
|
|
|
int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
|
|
|
|
if (*ngroups < 1) {
|
|
|
|
*ngroups = 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
groups[0] = group;
|
|
|
|
return (*ngroups = 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* getlogin() { // NOLINT: implementing bad function.
|
|
|
|
passwd *pw = getpwuid(getuid()); // NOLINT: implementing bad function in terms of bad function.
|
2017-07-29 01:27:49 +02:00
|
|
|
return pw ? pw->pw_name : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getlogin_r(char* buf, size_t size) {
|
|
|
|
char* login = getlogin();
|
|
|
|
if (login == nullptr) return errno;
|
|
|
|
size_t login_length = strlen(login) + 1;
|
|
|
|
if (login_length > size) return ERANGE;
|
|
|
|
memcpy(buf, login, login_length);
|
|
|
|
return 0;
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
2016-04-06 19:35:48 +02:00
|
|
|
void setpwent() {
|
2017-02-22 21:19:05 +01:00
|
|
|
passwd_state_t* state = get_passwd_tls_buffer();
|
2016-04-06 19:35:48 +02:00
|
|
|
if (state) {
|
|
|
|
state->getpwent_idx = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void endpwent() {
|
|
|
|
setpwent();
|
|
|
|
}
|
|
|
|
|
|
|
|
passwd* getpwent() {
|
2017-02-22 21:19:05 +01:00
|
|
|
passwd_state_t* state = get_passwd_tls_buffer();
|
2016-04-06 19:35:48 +02:00
|
|
|
if (state->getpwent_idx < 0) {
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-06 19:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t start = 0;
|
|
|
|
ssize_t end = android_id_count;
|
|
|
|
if (state->getpwent_idx < end) {
|
|
|
|
return android_iinfo_to_passwd(state, android_ids + state->getpwent_idx++);
|
|
|
|
}
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
|
|
|
|
|
|
|
|
if (state->getpwent_idx < end) {
|
|
|
|
return oem_id_to_passwd(
|
|
|
|
state->getpwent_idx++ - start + AID_OEM_RESERVED_START, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
|
|
|
|
|
|
|
|
if (state->getpwent_idx < end) {
|
|
|
|
return oem_id_to_passwd(
|
|
|
|
state->getpwent_idx++ - start + AID_OEM_RESERVED_2_START, state);
|
|
|
|
}
|
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
start = end;
|
|
|
|
end += AID_SYSTEM_EXT_RESERVED_END - AID_SYSTEM_RESERVED_START + 1;
|
|
|
|
|
|
|
|
if (state->getpwent_idx < end) {
|
|
|
|
// No one calls this enough to worry about how inefficient the below is.
|
|
|
|
auto* oem_passwd =
|
|
|
|
oem_id_to_passwd(state->getpwent_idx++ - start + AID_SYSTEM_RESERVED_START, state);
|
|
|
|
while (oem_passwd == nullptr && state->getpwent_idx < end) {
|
|
|
|
oem_passwd =
|
|
|
|
oem_id_to_passwd(state->getpwent_idx++ - start + AID_SYSTEM_RESERVED_START, state);
|
|
|
|
}
|
|
|
|
if (oem_passwd != nullptr) {
|
|
|
|
return oem_passwd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
state->getpwent_idx = get_next_app_id(state->getpwent_idx, false);
|
2016-04-06 19:35:48 +02:00
|
|
|
|
2017-11-14 17:50:43 +01:00
|
|
|
if (state->getpwent_idx != -1) {
|
|
|
|
return app_id_to_passwd(state->getpwent_idx, state);
|
2016-04-06 19:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// We are not reporting u1_a* and higher or we will be here forever
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-06 19:35:48 +02:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
static group* getgrgid_internal(gid_t gid, group_state_t* state) {
|
2019-04-24 22:35:39 +02:00
|
|
|
if (auto* android_id_info = find_android_id_info(gid); android_id_info != nullptr) {
|
|
|
|
return android_iinfo_to_group(state, android_id_info);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
2019-04-24 22:35:39 +02:00
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// Handle OEM range.
|
2019-04-24 22:35:39 +02:00
|
|
|
group* grp = oem_id_to_group(gid, state);
|
2018-08-03 02:31:13 +02:00
|
|
|
if (grp != nullptr) {
|
2016-04-05 18:09:46 +02:00
|
|
|
return grp;
|
|
|
|
}
|
|
|
|
return app_id_to_group(gid, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
group_state_t* state = get_group_tls_buffer();
|
2016-04-05 18:09:46 +02:00
|
|
|
return getgrgid_internal(gid, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static group* getgrnam_internal(const char* name, group_state_t* state) {
|
2019-04-24 22:35:39 +02:00
|
|
|
if (auto* android_id_info = find_android_id_info(name); android_id_info != nullptr) {
|
|
|
|
return android_iinfo_to_group(state, android_id_info);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
2018-02-03 01:10:07 +01:00
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
for (auto& group_file : group_files) {
|
|
|
|
if (group_file.FindByName(name, state)) {
|
2018-02-03 01:10:07 +01:00
|
|
|
return &state->group_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:09:46 +02:00
|
|
|
// Handle OEM range.
|
2019-04-24 22:35:39 +02:00
|
|
|
group* grp = oem_id_to_group(oem_id_from_name(name), state);
|
2018-08-03 02:31:13 +02:00
|
|
|
if (grp != nullptr) {
|
2016-04-05 18:09:46 +02:00
|
|
|
return grp;
|
|
|
|
}
|
|
|
|
return app_id_to_group(app_id_from_name(name, true), state);
|
|
|
|
}
|
|
|
|
|
|
|
|
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
|
pwd/grp: fix pwd _r reentrancy, new tests, clean up
getpwnam_r() and getpwuid_r() clobber the storage used by getpwnam()
and getpwuid(). This isn't likely to be a big issue, but since we do
this right for the group functions, fix this as well as add a test.
Both use more space in buf than is actually required, but well below
their sysconf() suggested values, so we accept that to keep the code
concise.
Add tests for dealing with unaligned input buffers, particularly for
getgrnam_r() and getgrgid_r(), as they require alignment but this
wasn't being tested.
Refactor common initialization code for both passwd and group state
structs.
Remove extraneous null pointer checks; the values they were testing
were offsets of a previous pointer, so guaranteed to never actually be
null. If the underlying pointer is actually null, we're beyond repair
anyway, so accept that we'll crash.
Test: pwd/grp unit tests
Change-Id: I60c4d00e9ab3cf55daf8314c5029fd914025b696
2019-05-15 02:02:28 +02:00
|
|
|
group_state_t* state = get_group_tls_buffer();
|
2016-04-05 18:09:46 +02:00
|
|
|
return getgrnam_internal(name, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getgroup_r(bool by_name, const char* name, gid_t gid, struct group* grp, char* buf,
|
|
|
|
size_t buflen, struct group** result) {
|
|
|
|
ErrnoRestorer errno_restorer;
|
2018-08-03 02:31:13 +02:00
|
|
|
*result = nullptr;
|
2016-04-05 18:09:46 +02:00
|
|
|
char* p = reinterpret_cast<char*>(
|
2017-10-06 01:39:33 +02:00
|
|
|
__BIONIC_ALIGN(reinterpret_cast<uintptr_t>(buf), sizeof(uintptr_t)));
|
2016-04-05 18:09:46 +02:00
|
|
|
if (p + sizeof(group_state_t) > buf + buflen) {
|
|
|
|
return ERANGE;
|
|
|
|
}
|
|
|
|
group_state_t* state = reinterpret_cast<group_state_t*>(p);
|
|
|
|
init_group_state(state);
|
|
|
|
group* retval = (by_name ? getgrnam_internal(name, state) : getgrgid_internal(gid, state));
|
2018-08-03 02:31:13 +02:00
|
|
|
if (retval != nullptr) {
|
2016-04-05 18:09:46 +02:00
|
|
|
*grp = *retval;
|
|
|
|
*result = grp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) {
|
2018-08-03 02:31:13 +02:00
|
|
|
return getgroup_r(false, nullptr, gid, grp, buf, buflen, result);
|
2016-04-05 18:09:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int getgrnam_r(const char* name, struct group* grp, char* buf, size_t buflen,
|
|
|
|
struct group **result) {
|
|
|
|
return getgroup_r(true, name, 0, grp, buf, buflen, result);
|
|
|
|
}
|
2016-04-06 19:35:48 +02:00
|
|
|
|
|
|
|
void setgrent() {
|
2017-02-22 21:19:05 +01:00
|
|
|
group_state_t* state = get_group_tls_buffer();
|
2016-04-06 19:35:48 +02:00
|
|
|
if (state) {
|
|
|
|
state->getgrent_idx = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void endgrent() {
|
|
|
|
setgrent();
|
|
|
|
}
|
|
|
|
|
|
|
|
group* getgrent() {
|
2017-02-22 21:19:05 +01:00
|
|
|
group_state_t* state = get_group_tls_buffer();
|
2016-04-06 19:35:48 +02:00
|
|
|
if (state->getgrent_idx < 0) {
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-06 19:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t start = 0;
|
|
|
|
ssize_t end = android_id_count;
|
|
|
|
if (state->getgrent_idx < end) {
|
|
|
|
return android_iinfo_to_group(state, android_ids + state->getgrent_idx++);
|
|
|
|
}
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
end += AID_OEM_RESERVED_END - AID_OEM_RESERVED_START + 1;
|
|
|
|
|
|
|
|
if (state->getgrent_idx < end) {
|
|
|
|
return oem_id_to_group(
|
|
|
|
state->getgrent_idx++ - start + AID_OEM_RESERVED_START, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
end += AID_OEM_RESERVED_2_END - AID_OEM_RESERVED_2_START + 1;
|
|
|
|
|
|
|
|
if (state->getgrent_idx < end) {
|
|
|
|
return oem_id_to_group(
|
|
|
|
state->getgrent_idx++ - start + AID_OEM_RESERVED_2_START, state);
|
|
|
|
}
|
|
|
|
|
2019-02-17 18:38:23 +01:00
|
|
|
start = end;
|
|
|
|
end += AID_SYSTEM_EXT_RESERVED_END - AID_SYSTEM_RESERVED_START + 1;
|
|
|
|
|
|
|
|
if (state->getgrent_idx < end) {
|
|
|
|
// No one calls this enough to worry about how inefficient the below is.
|
|
|
|
init_group_state(state);
|
|
|
|
auto* oem_group =
|
|
|
|
oem_id_to_group(state->getgrent_idx++ - start + AID_SYSTEM_RESERVED_START, state);
|
|
|
|
while (oem_group == nullptr && state->getgrent_idx < end) {
|
|
|
|
oem_group = oem_id_to_group(state->getgrent_idx++ - start + AID_SYSTEM_RESERVED_START, state);
|
|
|
|
}
|
|
|
|
if (oem_group != nullptr) {
|
|
|
|
return oem_group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 19:35:48 +02:00
|
|
|
start = end;
|
2016-12-13 22:03:19 +01:00
|
|
|
end += AID_USER_OFFSET - AID_APP_START; // Do not expose higher groups
|
2016-04-06 19:35:48 +02:00
|
|
|
|
2019-04-25 19:34:07 +02:00
|
|
|
state->getgrent_idx = get_next_app_id(state->getgrent_idx, true);
|
2017-11-14 17:50:43 +01:00
|
|
|
|
|
|
|
if (state->getgrent_idx != -1) {
|
|
|
|
return app_id_to_group(state->getgrent_idx, state);
|
2016-04-06 19:35:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// We are not reporting u1_a* and higher or we will be here forever
|
2018-08-03 02:31:13 +02:00
|
|
|
return nullptr;
|
2016-04-06 19:35:48 +02:00
|
|
|
}
|