| /* | |
| * Copyright (C) 2018 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "common/libs/utils/users.h" | |
| #include <grp.h> | |
| #include <pwd.h> | |
| #include <sys/types.h> | |
| #include <unistd.h> | |
| #include <algorithm> | |
| #include <cerrno> | |
| #include <cstdlib> | |
| #include <cstring> | |
| #include <mutex> | |
| #include <ostream> | |
| #include <string> | |
| #include <vector> | |
| #include <android-base/file.h> | |
| #include <android-base/logging.h> | |
| #include "common/libs/utils/contains.h" | |
| namespace cuttlefish { | |
| namespace { | |
| std::vector<gid_t> GetSuplementaryGroups() { | |
| int num_groups = getgroups(0, nullptr); | |
| if (num_groups < 0) { | |
| LOG(ERROR) << "Unable to get number of suplementary groups: " | |
| << std::strerror(errno); | |
| return {}; | |
| } | |
| std::vector<gid_t> groups(num_groups + 1); | |
| int retval = getgroups(groups.size(), groups.data()); | |
| if (retval < 0) { | |
| LOG(ERROR) << "Error obtaining list of suplementary groups (list size: " | |
| << groups.size() << "): " << std::strerror(errno); | |
| return {}; | |
| } | |
| return groups; | |
| } | |
| } // namespace | |
| gid_t GroupIdFromName(const std::string& group_name) { | |
| struct group grp{}; | |
| struct group* grp_p{}; | |
| std::vector<char> buffer(100); | |
| int result = 0; | |
| while(true) { | |
| result = getgrnam_r(group_name.c_str(), &grp, buffer.data(), buffer.size(), | |
| &grp_p); | |
| if (result != ERANGE) { | |
| break; | |
| } | |
| buffer.resize(2*buffer.size()); | |
| } | |
| if (result == 0) { | |
| if (grp_p != nullptr) { | |
| return grp.gr_gid; | |
| } else { | |
| // Caller may be checking with non-existent group name | |
| return -1; | |
| } | |
| } else { | |
| LOG(ERROR) << "Unable to get group id for group " << group_name << ": " | |
| << std::strerror(result); | |
| return -1; | |
| } | |
| } | |
| bool InGroup(const std::string& group) { | |
| auto gid = GroupIdFromName(group); | |
| if (gid == static_cast<gid_t>(-1)) { | |
| return false; | |
| } | |
| if (gid == getegid()) { | |
| return true; | |
| } | |
| auto groups = GetSuplementaryGroups(); | |
| return Contains(groups, gid); | |
| } | |
| Result<std::string> SystemWideUserHome(const uid_t uid) { | |
| // getpwuid() is not thread-safe, so we need a lock across all calls | |
| static std::mutex getpwuid_mutex; | |
| std::string home_dir; | |
| { | |
| std::lock_guard<std::mutex> lock(getpwuid_mutex); | |
| const auto entry = getpwuid(uid); | |
| if (entry) { | |
| home_dir = entry->pw_dir; | |
| } | |
| endpwent(); | |
| if (home_dir.empty()) { | |
| return CF_ERRNO("Failed to find the home directory using " << uid); | |
| } | |
| } | |
| std::string home_realpath; | |
| if (!android::base::Realpath(home_dir, &home_realpath)) { | |
| return CF_ERRNO("Failed to convert " << home_dir << " to its Realpath"); | |
| } | |
| return home_realpath; | |
| } | |
| Result<std::string> SystemWideUserHome() { | |
| return SystemWideUserHome(getuid()); | |
| } | |
| } // namespace cuttlefish |