Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
android /platform /bionic /refs/heads/main /. /libc /bionic /grp_pwd_file.cpp
blob: 1f45e80f28430be35e08de570c20c1be59fa1c2e [file] [log] [blame] [edit]
/*
* Copyright (C) 2018 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.
*/
#include"grp_pwd_file.h"
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
#include<sys/mman.h>
#include<sys/stat.h>
#include<async_safe/log.h>
#include"private/ErrnoRestorer.h"
#include"private/ScopedFd.h"
// This file mmap's /*/etc/passwd and /*/etc/group in order to return their contents without any
// allocations. Note that these files and the strings contained within them are explicitly not
// null-terminated. ':'s are used to deliminate fields and '\n's are used to deliminate lines.
// There is a check that the file ends with '\n', such that terminating loops at '\n' ensures that
// memory will be not read beyond the mmap region.
namespace{
voidCopyFieldToString(char* dest,constchar* source,size_t max){
while(*source!=':'&&*source!='\n'&& max>1){
*dest++=*source++;
--max;
}
*dest='\0';
}
boolFieldToUid(constchar* field,uid_t* uid){
if(field==nullptr){
returnfalse;
}
char* end=nullptr;
errno=0;
uid_t result= strtoul(field,&end,0);
if(errno!=0|| field== end||*end!=':'){
returnfalse;
}
*uid= result;
returntrue;
}
// Returns a pointer to one past the end of line.
constchar*ParseLine(constchar* begin,constchar* end,constchar** fields,size_t num_fields){
size_t fields_written=0;
constchar* position= begin;
fields[fields_written++]= position;
while(position< end&& fields_written< num_fields){
if(*position=='\n'){
return position+1;
}
if(*position==':'){
fields[fields_written++]= position+1;
}
position++;
}
while(position< end&&*position!='\n'){
position++;
}
return position+1;
}
structPasswdLine{
constchar* name()const{
return fields[0];
}
// Password is not supported.
constchar* uid()const{
return fields[2];
}
constchar* gid()const{
return fields[3];
}
// User Info is not supported
constchar* dir()const{
return fields[5];
}
constchar* shell()const{
return fields[6];
}
boolToPasswdState(passwd_state_t* passwd_state){
if(name()==nullptr|| dir()==nullptr|| shell()==nullptr){
returnfalse;
}
uid_t uid;
if(!FieldToUid(this->uid(),&uid)){
returnfalse;
}
gid_t gid;
if(!FieldToUid(this->gid(),&gid)){
returnfalse;
}
passwd_state->passwd_.pw_uid= uid;
passwd_state->passwd_.pw_gid= gid;
CopyFieldToString(passwd_state->name_buffer_, name(),sizeof(passwd_state->name_buffer_));
passwd_state->passwd_.pw_name= passwd_state->name_buffer_;
passwd_state->passwd_.pw_passwd=nullptr;
#ifdef __LP64__
passwd_state->passwd_.pw_gecos=nullptr;
#endif
CopyFieldToString(passwd_state->dir_buffer_, dir(),sizeof(passwd_state->dir_buffer_));
passwd_state->passwd_.pw_dir= passwd_state->dir_buffer_;
CopyFieldToString(passwd_state->sh_buffer_, shell(),sizeof(passwd_state->sh_buffer_));
passwd_state->passwd_.pw_shell= passwd_state->sh_buffer_;
returntrue;
}
staticconstexprsize_t kNumFields=7;
constchar* fields[kNumFields]={};
};
structGroupLine{
constchar* name()const{
return fields[0];
}
// Password is not supported.
constchar* gid()const{
return fields[2];
}
// User list is not supported (returns simply name)
boolToGroupState(group_state_t* group_state){
if(name()==nullptr|| gid()==nullptr){
returnfalse;
}
gid_t gid;
if(!FieldToUid(this->gid(),&gid)){
returnfalse;
}
group_state->group_.gr_gid= gid;
CopyFieldToString(group_state->group_name_buffer_, name(),
sizeof(group_state->group_name_buffer_));
group_state->group_.gr_name= group_state->group_name_buffer_;
group_state->group_.gr_passwd=nullptr;
group_state->group_.gr_mem= group_state->group_members_;
group_state->group_.gr_mem[0]= group_state->group_.gr_name;
group_state->group_.gr_mem[1]=nullptr;
returntrue;
}
staticconstexprsize_t kNumFields=4;
constchar* fields[kNumFields]={};
};
}// namespace
MmapFile::MmapFile(constchar* filename,constchar* required_prefix)
: filename_(filename), required_prefix_(required_prefix){
lock_.init(false);
}
voidMmapFile::Unmap(){
if(status_==FileStatus::Initialized){
size_t size= end_- start_+1;
munmap(const_cast<char*>(start_), size);
status_=FileStatus::Uninitialized;
start_=nullptr;
end_=nullptr;
}
}
boolMmapFile::GetFile(constchar** start,constchar** end){
LockGuard guard(lock_);
if(status_==FileStatus::Initialized){
*start= start_;
*end= end_;
returntrue;
}
if(status_==FileStatus::Error){
returnfalse;
}
if(!DoMmap()){
status_=FileStatus::Error;
returnfalse;
}
status_=FileStatus::Initialized;
*start= start_;
*end= end_;
returntrue;
}
boolMmapFile::DoMmap(){
ScopedFd fd(open(filename_, O_CLOEXEC| O_NOFOLLOW| O_RDONLY));
struct stat fd_stat;
if(fstat(fd.get(),&fd_stat)==-1){
returnfalse;
}
auto mmap_size= fd_stat.st_size;
void* map_result= mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd.get(),0);
if(map_result== MAP_FAILED){
returnfalse;
}
start_=static_cast<constchar*>(map_result);
end_= start_+ mmap_size-1;
if(*end_!='\n'){
munmap(map_result, mmap_size);
returnfalse;
}
returntrue;
}
template<typenameLine,typenamePredicate>
boolMmapFile::Find(Line* line,Predicate predicate){
constchar* start;
constchar* end;
if(!GetFile(&start,&end)){
returnfalse;
}
constchar* line_beginning= start;
while(line_beginning< end){
line_beginning=ParseLine(line_beginning, end, line->fields, line->kNumFields);
#if defined(__ANDROID__)
// To comply with Treble, users/groups from each partition need to be prefixed with
// the partition name.
if(required_prefix_!=nullptr){
if(strncmp(line->fields[0], required_prefix_, strlen(required_prefix_))!=0){
char name[kGrpPwdBufferSize];
CopyFieldToString(name, line->fields[0],sizeof(name));
async_safe_format_log(ANDROID_LOG_ERROR,"libc",
"Found user/group name '%s' in '%s' without required prefix '%s'",
name, filename_, required_prefix_);
continue;
}
}
#endif
if(predicate(line))returntrue;
}
returnfalse;
}
template<typenameLine>
boolMmapFile::FindById(uid_t uid,Line* line){
returnFind(line,[uid](constauto& line){
uid_t line_id;
if(!FieldToUid(line->fields[2],&line_id)){
returnfalse;
}
return line_id== uid;
});
}
template<typenameLine>
boolMmapFile::FindByName(constchar* name,Line* line){
returnFind(line,[name](constauto& line){
constchar* line_name= line->fields[0];
if(line_name==nullptr){
returnfalse;
}
constchar* match_name= name;
while(*line_name!='\n'&&*line_name!=':'&&*match_name!='\0'){
if(*line_name++!=*match_name++){
returnfalse;
}
}
return*line_name==':'&&*match_name=='\0';
});
}
PasswdFile::PasswdFile(constchar* filename,constchar* required_prefix)
: mmap_file_(filename, required_prefix){
}
boolPasswdFile::FindById(uid_t id,passwd_state_t* passwd_state){
ErrnoRestorer errno_restorer;
PasswdLine passwd_line;
return mmap_file_.FindById(id,&passwd_line)&& passwd_line.ToPasswdState(passwd_state);
}
boolPasswdFile::FindByName(constchar* name,passwd_state_t* passwd_state){
ErrnoRestorer errno_restorer;
PasswdLine passwd_line;
return mmap_file_.FindByName(name,&passwd_line)&& passwd_line.ToPasswdState(passwd_state);
}
GroupFile::GroupFile(constchar* filename,constchar* required_prefix)
: mmap_file_(filename, required_prefix){
}
boolGroupFile::FindById(gid_t id,group_state_t* group_state){
ErrnoRestorer errno_restorer;
GroupLine group_line;
return mmap_file_.FindById(id,&group_line)&& group_line.ToGroupState(group_state);
}
boolGroupFile::FindByName(constchar* name,group_state_t* group_state){
ErrnoRestorer errno_restorer;
GroupLine group_line;
return mmap_file_.FindByName(name,&group_line)&& group_line.ToGroupState(group_state);
}

[8]ページ先頭

©2009-2025 Movatter.jp