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/shared_dirs.h"
7 #include <boost/filesystem/operations.hpp>
8 #include <boost/filesystem/path.hpp>
9 #include <boost/program_options.hpp>
10 #include <boost/system/error_code.hpp>
14 #include <manifest_parser/utils/logging.h>
15 #include <vcore/Certificate.h>
16 #include <pkgmgr-info.h>
19 #include <sys/types.h>
22 #include <tzplatform_config.h>
23 #include <sys/xattr.h>
24 #include <gum/gum-user.h>
25 #include <gum/gum-user-service.h>
26 #include <gum/common/gum-user-types.h>
40 #include "common/paths.h"
41 #include "common/security_registration.h"
42 #include "common/pkgmgr_query.h"
43 #include "common/utils/base64.h"
44 #include "common/utils/file_util.h"
45 #include "common/utils/glist_range.h"
47 namespace bf = boost::filesystem;
48 namespace bpo = boost::program_options;
49 namespace bs = boost::system;
50 namespace ci = common_installer;
54 typedef std::vector<std::tuple<uid_t, gid_t, bf::path>> user_list;
55 const std::vector<const char*> kEntries = {
63 const char kTrustedDir[] = "shared/trusted";
64 const char kSkelAppDir[] = "/etc/skel/apps_rw";
65 const char kPackagePattern[] = R"(^[0-9a-zA-Z_-]+(\.?[0-9a-zA-Z_-]+)*$)";
66 const int32_t kPWBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
67 const int32_t kGRBufSize = sysconf(_SC_GETGR_R_SIZE_MAX);
69 bool ValidateTizenPackageId(const std::string& id) {
70 std::regex package_regex(kPackagePattern);
71 return std::regex_match(id, package_regex);
74 int PkgmgrListCallback(const pkgmgrinfo_pkginfo_h handle, void *user_data) {
75 auto pkgs = reinterpret_cast<ci::PkgList*>(user_data);
76 char* pkgid = nullptr;
77 if (pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid) != PMINFO_R_OK) {
81 if (pkgmgrinfo_pkginfo_get_api_version(handle, &api_version) != PMINFO_R_OK) {
84 pkgmgrinfo_certinfo_h cert_handle;
85 if (pkgmgrinfo_pkginfo_create_certinfo(&cert_handle) != PMINFO_R_OK) {
88 if (pkgmgrinfo_pkginfo_load_certinfo(pkgid, cert_handle, 0) != PMINFO_R_OK) {
89 pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
92 const char* author_cert;
93 if (pkgmgrinfo_pkginfo_get_cert_value(cert_handle, PMINFO_AUTHOR_SIGNER_CERT,
94 &author_cert) != PMINFO_R_OK) {
95 pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
99 ValidationCore::Certificate cert(author_cert,
100 ValidationCore::Certificate::FORM_BASE64);
101 unsigned char* public_key;
103 cert.getPublicKeyDER(&public_key, &len);
104 std::string author_id =
105 ci::EncodeBase64(reinterpret_cast<const char*>(public_key));
106 pkgs->emplace_back(pkgid, api_version, author_id);
108 pkgs->emplace_back(pkgid, std::string(), std::string());
111 pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
116 ci::PkgList GetAllGlobalAppsInformation() {
118 if (pkgmgrinfo_pkginfo_get_usr_list(&PkgmgrListCallback,
119 &pkgs, tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) != PMINFO_R_OK) {
120 LOG(ERROR) << "Failed to query global application list";
126 ci::PkgList GetPkgInformation(uid_t uid, const std::string& pkgid) {
127 if (!ValidateTizenPackageId(pkgid)) {
128 LOG(DEBUG) << "Package id validation failed. pkgid = " << pkgid;
129 return ci::PkgList();
133 pkgmgrinfo_pkginfo_h handle;
134 if (pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid.c_str(), uid, &handle) !=
136 LOG(DEBUG) << "pkgmgrinfo_pkginfo_get_pkginfo failed, for pkgid=" << pkgid;
139 if (PkgmgrListCallback(handle, &pkgs) != 0) {
140 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
141 LOG(DEBUG) << "PkgmgrListCallback failed";
144 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
148 bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
150 bs::error_code error;
151 bf::perms perms = bf::owner_read |
154 if (bf::is_directory(subpath)) {
155 perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
157 bf::permissions(subpath, perms, error);
159 LOG(ERROR) << "Failed to set permissions for: " << subpath;
162 int fd = open(subpath.c_str(), O_RDONLY);
164 LOG(ERROR) << "Can't open directory : " << subpath;
167 int ret = fchown(fd, uid, gid);
170 LOG(ERROR) << "Failed to change owner of: " << subpath;
176 bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
178 uid_t uid, gid_t gid, const bool set_permissions) {
179 bf::path base_dir = app_dir / pkgid;
180 if (bf::exists(base_dir)) {
181 LOG(DEBUG) << "Directory for user already exist: " << base_dir;
185 bs::error_code error;
186 std::vector<const char*> dirs(kEntries);
188 dirs.push_back(kTrustedDir);
189 for (auto& entry : dirs) {
190 bf::path subpath = base_dir / entry;
191 bf::create_directories(subpath, error);
193 LOG(ERROR) << "Failed to create directory: " << subpath;
197 if (set_permissions) {
198 if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
202 for (bf::recursive_directory_iterator iter(subpath);
203 iter != bf::recursive_directory_iterator(); ++iter) {
204 if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
213 bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
215 struct passwd *pwd_result;
216 char buf[kPWBufSize];
217 int ret = getpwuid_r(user, &pwd, buf, sizeof(buf), &pwd_result);
218 if (ret != 0 || pwd_result == nullptr)
222 apps_rw = bf::path(apps_prefix.c_str()) / pwd.pw_name / "apps_rw";
227 bool CreateUserDirectories(uid_t user, const std::string& pkgid,
229 const std::string& apps_prefix, const bool set_permissions) {
231 struct passwd *pwd_result;
232 char buf_pw[kPWBufSize];
233 int ret = getpwuid_r(user, &pwd, buf_pw, sizeof(buf_pw), &pwd_result);
234 if (ret != 0 || pwd_result == nullptr) {
235 LOG(WARNING) << "Failed to get user for home directory: " << user;
240 struct group *gr_result;
241 char buf_gr[kGRBufSize];
242 ret = getgrgid_r(pwd.pw_gid, &gr, buf_gr, sizeof(buf_gr), &gr_result);
244 || strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
247 LOG(DEBUG) << "Creating directories for uid: " << pwd.pw_uid << ", gid: "
250 bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
251 if (apps_rw.empty()) {
252 LOG(DEBUG) << "Directory not exists: " << apps_rw;
256 if (!CreateDirectories(apps_rw, pkgid, trusted,
257 pwd.pw_uid, pwd.pw_gid, set_permissions)) {
263 bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
264 bf::path base_dir = app_dir / pkgid;
265 bs::error_code error;
266 bf::remove_all(base_dir, error);
268 LOG(ERROR) << "Failed to delete directory: " << base_dir;
274 user_list GetUserList() {
275 GumUserService* service =
276 gum_user_service_create_sync((getuid() == 0) ? TRUE : FALSE);
277 gchar** user_type_strv = gum_user_type_to_strv(
278 GUM_USERTYPE_ADMIN | GUM_USERTYPE_GUEST | GUM_USERTYPE_NORMAL);
279 GumUserList* gum_user_list =
280 gum_user_service_get_user_list_sync(service, user_type_strv);
282 for (GumUser* guser : GListRange<GumUser*>(gum_user_list)) {
284 g_object_get(G_OBJECT(guser), "uid", &uid, nullptr);
286 g_object_get(G_OBJECT(guser), "gid", &gid, nullptr);
287 gchar* homedir = nullptr;
288 g_object_get(G_OBJECT(guser), "homedir", &homedir, nullptr);
289 if (homedir == nullptr) {
290 LOG(WARNING) << "No homedir for uid: " << uid;
293 list.emplace_back(uid, gid, bf::path(homedir));
295 g_strfreev(user_type_strv);
296 gum_user_service_list_free(gum_user_list);
302 namespace common_installer {
304 std::string GetDirectoryPathForInternalStorage() {
305 const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
306 if (internal_storage_prefix)
307 return std::string(internal_storage_prefix);
308 return tzplatform_getenv(TZ_SYS_HOME);
311 std::string GetDirectoryPathForExternalStorage() {
312 return GetExternalCardPath().string();
315 bool PerformInternalDirectoryCreationForUser(uid_t user,
316 const std::string& pkgid,
318 const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
319 const bool set_permissions = true;
320 if (!CreateUserDirectories(user, pkgid, trusted,
321 internal_storage_prefix, set_permissions))
326 bool PerformExternalDirectoryCreationForUser(uid_t user,
327 const std::string& pkgid) {
328 bf::path storage_path = GetExternalCardPath();
330 // TODO(t.iwanek): trusted in this context means that we have signature
331 // this argument is not longer needed as all package must be signed
332 // so that trusted directory may be labeled correctly by security-manager in
333 // all cases. This parameter and its propagation should be removed.
336 const bool set_permissions = false;
337 if (!bf::exists(storage_path)) {
338 LOG(WARNING) << "External storage (SD Card) is not mounted.";
342 bf::path storage_apps_path = storage_path / "apps";
343 if (!bf::exists(storage_apps_path)) {
344 bs::error_code error;
345 bf::create_directories(storage_apps_path, error);
347 LOG(ERROR) << "Failed to create directory: "
348 << storage_apps_path.c_str();
353 if (CreateUserDirectories(user, pkgid, trusted,
354 storage_apps_path.c_str(), set_permissions)) {
359 bool PerformExternalDirectoryDeletionForUser(uid_t user,
360 const std::string& pkgid) {
361 bf::path storage_path = GetExternalCardPath();
362 if (!bf::exists(storage_path)) {
363 LOG(WARNING) << "External storage (SD Card) is not mounted.";
367 bf::path storage_apps_path = bf::path(storage_path) / "apps";
368 return DeleteDirectories(
369 GetDirectoryPathForStorage(user, storage_apps_path.string()), pkgid);
372 bool PerformInternalDirectoryCreationForAllUsers(const std::string& pkgid,
374 user_list list = GetUserList();
375 for (auto l : list) {
376 if (!PerformInternalDirectoryCreationForUser(std::get<0>(l),
379 LOG(ERROR) << "Could not create internal storage directories for user: "
385 bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid) {
386 user_list list = GetUserList();
387 for (auto l : list) {
388 if (!PerformExternalDirectoryCreationForUser(std::get<0>(l),
390 LOG(WARNING) << "Could not create external storage directories for user: "
396 bool PerformExternalDirectoryDeletionForAllUsers(const std::string& pkgid) {
397 user_list list = GetUserList();
398 for (auto l : list) {
399 uid_t uid = std::get<0>(l);
400 LOG(DEBUG) << "Deleting directories for user: " << uid;
401 if (QueryIsPackageInstalled(pkgid, uid)) {
402 LOG(DEBUG) << "Package: " << pkgid << " for uid: " << uid
403 << " still exists. Skipping";
407 if (!PerformExternalDirectoryDeletionForUser(uid, pkgid))
408 LOG(WARNING) << "Could not delete external storage directories for user: "
414 bool CreateSkelDirectories(const std::string& pkgid) {
415 bf::path path = bf::path(kSkelAppDir) / pkgid;
416 LOG(DEBUG) << "Creating directories in: " << path;
417 bs::error_code error;
418 bf::create_directories(path, error);
421 LOG(ERROR) << "Failed to create directory: " << path;
425 for (auto& entry : kEntries) {
426 bf::path subpath = path / entry;
427 bf::create_directories(subpath, error);
428 if (error && !bf::exists(subpath)) {
429 LOG(ERROR) << "Failed to create directory: " << subpath;
434 std::string error_message;
435 if (!RegisterSecurityContextForPath(pkgid, path,
436 tzplatform_getuid(TZ_SYS_GLOBALAPP_USER), &error_message)) {
437 LOG(ERROR) << "Failed to register security context for path: " << path
438 << ", error_message: " << error_message;
446 bool DeleteSkelDirectories(const std::string& pkgid) {
447 return DeleteDirectories(bf::path(kSkelAppDir), pkgid);
451 bool DeleteUserDirectories(const std::string& pkgid) {
452 user_list list = GetUserList();
453 for (auto l : list) {
454 if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
455 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
459 LOG(DEBUG) << "Deleting directories of " << pkgid
460 << ", for uid: " << std::get<0>(l);
461 bf::path apps_rw(std::get<2>(l) / "apps_rw");
462 if (!DeleteDirectories(apps_rw, pkgid)) {
469 bool DeleteUserExternalDirectories(const std::string& pkgid) {
470 user_list list = GetUserList();
471 for (auto l : list) {
472 if (ci::QueryIsPackageInstalled(pkgid, std::get<0>(l))) {
473 LOG(INFO) << pkgid << " is installed for user " << std::get<0>(l);
477 LOG(DEBUG) << "Deleting external directories of " << pkgid
478 << ", for uid: " << std::get<0>(l);
479 bf::path apps_rw(std::get<2>(l) / "apps_rw");
480 if (!DeleteDirectories(apps_rw, pkgid)) {
488 bool CopyUserDirectories(const std::string& pkgid) {
489 user_list list = GetUserList();
490 for (auto l : list) {
491 LOG(DEBUG) << "Copying directories for uid: " << std::get<0>(l);
492 bf::path apps_rw(std::get<2>(l) / "apps_rw");
493 bf::path src = bf::path(kSkelAppDir) / pkgid;
494 bf::path dst = apps_rw / pkgid;
495 if (!ci::CopyDir(src, dst, FS_COPY_XATTR))
497 if (!SetPackageDirectoryOwnerAndPermissions(dst, std::get<0>(l),
500 for (bf::recursive_directory_iterator iter(dst);
501 iter != bf::recursive_directory_iterator(); ++iter) {
502 if (!SetPackageDirectoryOwnerAndPermissions(iter->path(),
503 std::get<0>(l), std::get<1>(l)))
510 ci::PkgList CreatePkgInformationList(uid_t uid,
511 const std::vector<std::string>& pkgs) {
512 return pkgs.empty() ?
513 GetAllGlobalAppsInformation() : GetPkgInformation(uid, *pkgs.begin());
516 } // namespace common_installer