Merge "Add default permission of directory for global pkg to 755" into tizen_3.0
[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       GUM_USERTYPE_SECURITY);
39   GumUserService* service = nullptr;
40   GumUserList* gum_user_list = nullptr;
41   int count = 0;
42   // FIXME: Temporary retry logic, this should be removed
43   while (count < kRetryMax) {
44     service = gum_user_service_create_sync((getuid() == 0) ? TRUE : FALSE);
45     if (service == nullptr) {
46       count++;
47       LOG(WARNING) << "Failed to create gum user service! ("
48                    << count << "/" << kRetryMax << ")";
49       usleep(kRetryDelay);
50       continue;
51     }
52
53     gum_user_list =
54         gum_user_service_get_user_list_sync(service, user_type_strv);
55     if (gum_user_list == nullptr) {
56       g_object_unref(service);
57       count++;
58       LOG(WARNING) << "Failed to get gum user list! ("
59                    << count << "/" << kRetryMax << ")";
60       usleep(kRetryDelay);
61       continue;
62     } else {
63       break;
64     }
65   }
66   UserList list;
67   for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
68     uid_t uid;
69     g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
70     gid_t gid;
71     g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
72     gchar* homedir = nullptr;
73     g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
74     if (homedir == nullptr) {
75       LOG(WARNING) << "No homedir for uid: " << uid;
76       continue;
77     }
78     list.emplace_back(uid, gid, bf::path(homedir));
79   }
80   g_strfreev(user_type_strv);
81   gum_user_service_list_free(gum_user_list);
82   g_object_unref(service);
83   return list;
84 }
85
86 bool IsAdminUser(uid_t uid) {
87   GumUser* guser;
88   int count = 0;
89   do {
90     guser = gum_user_get_sync(uid, (getuid() == 0) ? TRUE : FALSE);
91     if (guser)
92       break;
93     count++;
94     LOG(WARNING) << "Failed to get gum user! ("
95                  << count << "/" << kRetryMax << ")";
96     usleep(kRetryDelay);
97   } while (count < kRetryMax);
98   if (!guser)
99     return false;
100   GumUserType ut;
101   g_object_get(G_OBJECT(guser), "usertype", &ut, NULL);
102   bool is_admin;
103   if (ut == GUM_USERTYPE_ADMIN)
104     is_admin = true;
105   else
106     is_admin = false;
107   g_object_unref(guser);
108   return is_admin;
109 }
110
111 boost::optional<gid_t> GetGidByGroupName(const char* groupname) {
112   boost::optional<gid_t> result;
113   char buf[kGRBufSize];
114   struct group entry;
115   struct group* ge;
116   int ret = getgrnam_r(groupname, &entry, buf, sizeof(buf), &ge);
117   if (ret || ge == nullptr) {
118     return result;
119   }
120   result = entry.gr_gid;
121   return result;
122 }
123
124 std::string GetUsernameByUid(uid_t user) {
125   struct passwd pwd;
126   struct passwd* pwd_result;
127   char buf[kPWBufSize];
128   int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
129   if (ret != 0 || pwd_result == nullptr)
130     return {};
131   return pwd.pw_name;
132 }
133
134 boost::optional<uid_t> GetUidByUserName(const char* username) {
135   struct passwd pwd;
136   struct passwd* pwd_result;
137   char buf[kPWBufSize];
138   int ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &pwd_result);
139   if (ret != 0 || pwd_result == nullptr)
140     return {};
141   return pwd.pw_uid;
142 }
143
144 boost::optional<gid_t> GetGidByUid(uid_t uid) {
145   boost::optional<gid_t> result;
146   struct passwd pwd;
147   struct passwd* pwd_result;
148   char buf[kPWBufSize];
149   int ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
150   if (ret != 0 || pwd_result == nullptr)
151     return result;
152   result = pwd.pw_gid;
153   return result;
154 }
155
156 std::string GetGroupNameByGid(gid_t gid) {
157   char buf[kGRBufSize];
158   struct group entry;
159   struct group* ge;
160   int ret = getgrgid_r(gid, &entry, buf, sizeof(buf), &ge);
161   if (ret || ge == nullptr) {
162     return {};
163   }
164   return entry.gr_name;
165 }
166
167 }  // namespace common_installer