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