| /* |
| * 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 |