Move GetLightUserList() to user_util.h
[platform/core/appfw/app-installers.git] / src / common / utils / user_util.cc
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.
4
5 #include "common/utils/user_util.h"
6
7 #include <manifest_parser/utils/logging.h>
8 #include <sessiond.h>
9
10 #include <boost/filesystem/path.hpp>
11
12 #include <glib.h>
13 #include <grp.h>
14 #include <gum/gum-user.h>
15 #include <gum/gum-user-service.h>
16 #include <gum/common/gum-user-types.h>
17
18 #include <vector>
19
20 #include "common/utils/glist_range.h"
21
22 namespace bf = boost::filesystem;
23
24 namespace {
25
26 const int32_t kPWBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
27 const int32_t kGRBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
28
29 const int kRetryMax = 5;
30 const int kRetryDelay = 1000000 / 2;
31
32 }
33
34 namespace common_installer {
35
36 UserList GetUserList() {
37   gchar** user_type_strv = gum_user_type_to_strv(
38       GUM_USERTYPE_ADMIN | GUM_USERTYPE_GUEST | GUM_USERTYPE_NORMAL);
39   GumUserService* service = nullptr;
40   GumUserList* gum_user_list = nullptr;
41   int count = 0;
42   bool is_offline = getuid() == 0;
43   // FIXME: Temporary retry logic, this should be removed
44   while (count < kRetryMax) {
45     service = gum_user_service_create_sync(is_offline ? TRUE : FALSE);
46     if (service == nullptr) {
47       if (is_offline) {
48         LOG(WARNING) << "Failed to create gum user service!";
49         break;
50       }
51       count++;
52       LOG(WARNING) << "Failed to create gum user service! ("
53                    << count << "/" << kRetryMax << ")";
54       usleep(kRetryDelay);
55       continue;
56     }
57
58     gum_user_list =
59         gum_user_service_get_user_list_sync(service, user_type_strv);
60     g_object_unref(service);
61     if (gum_user_list == nullptr) {
62       if (is_offline) {
63         LOG(WARNING) << "Failed to get gum user list!";
64         break;
65       }
66       count++;
67       LOG(WARNING) << "Failed to get gum user list! ("
68                    << count << "/" << kRetryMax << ")";
69       usleep(kRetryDelay);
70       continue;
71     } else {
72       break;
73     }
74   }
75   if (gum_user_list == nullptr) {
76     g_strfreev(user_type_strv);
77     return {};
78   }
79
80   UserList list;
81   for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
82     uid_t uid;
83     g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
84     gid_t gid;
85     g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
86     gchar* homedir = nullptr;
87     g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
88     if (homedir == nullptr) {
89       LOG(WARNING) << "No homedir for uid: " << uid;
90       continue;
91     }
92     list.emplace_back(uid, gid, bf::path(homedir));
93     g_free(homedir);
94   }
95   g_strfreev(user_type_strv);
96   gum_user_service_list_free(gum_user_list);
97   return list;
98 }
99
100 boost::optional<bool> IsAdminUser(uid_t uid) {
101   GumUser* guser;
102   int count = 0;
103   bool is_offline = getuid() == 0;
104   do {
105     guser = gum_user_get_sync(uid, is_offline ? TRUE : FALSE);
106     if (guser)
107       break;
108     if (is_offline) {
109       LOG(WARNING) << "Failed to get gum user!";
110       break;
111     }
112     count++;
113     LOG(WARNING) << "Failed to get gum user! ("
114                  << count << "/" << kRetryMax << ")";
115     usleep(kRetryDelay);
116   } while (count < kRetryMax);
117   if (!guser)
118     return {};
119   GumUserType ut;
120   g_object_get(G_OBJECT(guser), "usertype", &ut, NULL);
121   bool is_admin;
122   if (ut == GUM_USERTYPE_ADMIN)
123     is_admin = true;
124   else
125     is_admin = false;
126   g_object_unref(guser);
127   return is_admin;
128 }
129
130 boost::optional<gid_t> GetGidByGroupName(const char* groupname) {
131   char buf[kGRBufSize];
132   struct group entry;
133   struct group* ge;
134   int ret = getgrnam_r(groupname, &entry, buf, sizeof(buf), &ge);
135   if (ret || ge == nullptr)
136     return {};
137   return entry.gr_gid;
138 }
139
140 std::string GetUsernameByUid(uid_t user) {
141   struct passwd pwd;
142   struct passwd* pwd_result;
143   char buf[kPWBufSize];
144   int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
145   if (ret != 0 || pwd_result == nullptr)
146     return {};
147   return pwd.pw_name;
148 }
149
150 boost::optional<uid_t> GetUidByUserName(const char* username) {
151   struct passwd pwd;
152   struct passwd* pwd_result;
153   char buf[kPWBufSize];
154   int ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_result);
155   if (ret != 0 || pwd_result == nullptr)
156     return {};
157   return pwd.pw_uid;
158 }
159
160 boost::optional<gid_t> GetGidByUid(uid_t uid) {
161   struct passwd pwd;
162   struct passwd* pwd_result;
163   char buf[kPWBufSize];
164   int ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
165   if (ret != 0 || pwd_result == nullptr)
166     return {};
167   return pwd.pw_gid;
168 }
169
170 std::string GetGroupNameByGid(gid_t gid) {
171   char buf[kGRBufSize];
172   struct group entry;
173   struct group* ge;
174   int ret = getgrgid_r(gid, &entry, buf, sizeof(buf), &ge);
175   if (ret || ge == nullptr) {
176     return {};
177   }
178   return entry.gr_name;
179 }
180
181 std::vector<std::string> GetLightUserList(uid_t uid) {
182   int user_count = 0;
183   subsession_user_t* user_list = nullptr;
184   int ret = subsession_get_user_list(
185       static_cast<int>(uid), &user_list, &user_count);
186   if (ret != TIZEN_ERROR_NONE) {
187     LOG(ERROR) << "Failed to get light user list : " << ret;
188     return {};
189   }
190
191   std::vector<std::string> result_list;
192   for (int i = 0; i < user_count; i++) {
193     if (strlen(user_list[i]) == 0)
194       continue;
195
196     result_list.emplace_back(user_list[i]);
197   }
198
199   std::free(user_list);
200   return result_list;
201 }
202
203 }  // namespace common_installer