1 // Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
5 #include "common/utils/user_util.h"
7 #include <manifest_parser/utils/logging.h>
8 #include <tzplatform_config.h>
12 #include <gum/gum-user.h>
13 #include <gum/gum-user-service.h>
14 #include <gum/common/gum-user-types.h>
19 #include "common/utils/file_util.h"
20 #include "common/utils/glist_range.h"
22 namespace fs = std::filesystem;
26 const int32_t kPWBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
27 const int32_t kGRBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
29 const int kRetryMax = 5;
30 const int kRetryDelay = 1000000 / 2;
32 const char kSubsessionDir[] = "subsession";
36 namespace common_installer {
38 UserList GetUserList() {
39 gchar** user_type_strv = gum_user_type_to_strv(
40 GUM_USERTYPE_ADMIN | GUM_USERTYPE_GUEST | GUM_USERTYPE_NORMAL);
41 GumUserService* service = nullptr;
42 GumUserList* gum_user_list = nullptr;
44 bool is_offline = getuid() == 0;
45 // FIXME: Temporary retry logic, this should be removed
46 while (count < kRetryMax) {
47 service = gum_user_service_create_sync(is_offline ? TRUE : FALSE);
48 if (service == nullptr) {
50 LOG(WARNING) << "Failed to create gum user service!";
54 LOG(WARNING) << "Failed to create gum user service! ("
55 << count << "/" << kRetryMax << ")";
61 gum_user_service_get_user_list_sync(service, user_type_strv);
62 g_object_unref(service);
63 if (gum_user_list == nullptr) {
65 LOG(WARNING) << "Failed to get gum user list!";
69 LOG(WARNING) << "Failed to get gum user list! ("
70 << count << "/" << kRetryMax << ")";
77 if (gum_user_list == nullptr) {
78 g_strfreev(user_type_strv);
83 for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
85 g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
87 g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
88 gchar* homedir = nullptr;
89 g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
90 if (homedir == nullptr) {
91 LOG(WARNING) << "No homedir for uid: " << uid;
94 list.emplace_back(uid, gid, fs::path(homedir));
97 g_strfreev(user_type_strv);
98 gum_user_service_list_free(gum_user_list);
102 std::optional<bool> IsAdminUser(uid_t uid) {
105 bool is_offline = getuid() == 0;
107 guser = gum_user_get_sync(uid, is_offline ? TRUE : FALSE);
111 LOG(WARNING) << "Failed to get gum user!";
115 LOG(WARNING) << "Failed to get gum user! ("
116 << count << "/" << kRetryMax << ")";
118 } while (count < kRetryMax);
122 g_object_get(G_OBJECT(guser), "usertype", &ut, NULL);
124 if (ut == GUM_USERTYPE_ADMIN)
128 g_object_unref(guser);
132 std::optional<gid_t> GetGidByGroupName(const char* groupname) {
133 char buf[kGRBufSize];
136 int ret = getgrnam_r(groupname, &entry, buf, sizeof(buf), &ge);
137 if (ret || ge == nullptr)
142 std::string GetUsernameByUid(uid_t user) {
144 struct passwd* pwd_result;
145 char buf[kPWBufSize];
146 int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
147 if (ret != 0 || pwd_result == nullptr)
152 std::optional<uid_t> GetUidByUserName(const char* username) {
154 struct passwd* pwd_result;
155 char buf[kPWBufSize];
156 int ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_result);
157 if (ret != 0 || pwd_result == nullptr)
162 std::optional<gid_t> GetGidByUid(uid_t uid) {
164 struct passwd* pwd_result;
165 char buf[kPWBufSize];
166 int ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
167 if (ret != 0 || pwd_result == nullptr)
172 std::string GetGroupNameByGid(gid_t gid) {
173 char buf[kGRBufSize];
176 int ret = getgrgid_r(gid, &entry, buf, sizeof(buf), &ge);
177 if (ret || ge == nullptr) {
180 return entry.gr_name;
183 std::vector<std::string> GetLightUserList(uid_t uid) {
184 std::string username = GetUsernameByUid(uid);
185 if (username.empty()) {
186 LOG(ERROR) << "Failed to get user name of uid: " << uid;
190 tzplatform_set_user(uid);
191 fs::path subsession_dir =
192 fs::path(tzplatform_getenv(TZ_USER_HOME)) / kSubsessionDir;
193 tzplatform_reset_user();
195 // Get subsuession user list by directory name instead of using sessiond API
196 // due to performance issue
197 return GetDirectoryList(subsession_dir);
200 } // namespace common_installer